fix WKT I/O error handling

This commit is contained in:
Laurent Rineau 2025-02-06 01:22:02 +01:00
parent 050677f002
commit 765744e8b2
2 changed files with 79 additions and 146 deletions

View File

@ -44,18 +44,42 @@ namespace internal {
template <typename K>
void pop_back_if_equal_to_front(CGAL::Polygon_2<K>& poly)
{
typename CGAL::Polygon_2<K>::iterator it = poly.end();
--it;
if((*poly.begin()) == *it)
poly.erase(it);
auto last_it = std::prev(poly.end());
if((*poly.begin()) == *last_it)
poly.erase(last_it);
}
template <typename K>
void pop_back_if_equal_to_front(CGAL::Polygon_with_holes_2<K>& pwh)
{
pop_back_if_equal_to_front(pwh.outer_boundary());
for(auto i = pwh.holes_begin(); i!= pwh.holes_end(); ++i)
pop_back_if_equal_to_front(*i);
for(auto& hole : pwh.holes())
pop_back_if_equal_to_front(hole);
}
template <typename Geometry>
bool read_wkt_or_fail_stream(std::istream& in,
const std::string& line,
Geometry& geometry)
{
try {
boost::geometry::read_wkt(line, geometry);
} catch(std::exception& e) {
std::cerr << "error: " << e.what() << std::endl;
in.clear(in.rdstate() | std::ios::failbit);
return false;
}
return true;
}
bool get_a_new_line(std::istream& in, std::string& line)
{
in >> std::ws; // skip whitespaces
if(in.good()) {
return !std::getline(in, line).fail();
} else {
return false;
}
}
} // namespace internal
@ -76,28 +100,12 @@ template<typename Point>
bool read_point_WKT(std::istream& in,
Point& point)
{
if(!in.good())
return false;
std::string line;
while(std::getline(in, line))
while(internal::get_a_new_line(in, line))
{
std::istringstream iss(line);
std::string type;
iss >> type;
if(type.substr(0, 5).compare("POINT") == 0)
if(line.substr(0, 5).compare("POINT") == 0)
{
try
{
boost::geometry::read_wkt(line, point);
}
catch(...)
{
std::cerr << "error." << std::endl;
return false;
}
internal::read_wkt_or_fail_stream(in, line, point);
break;
}
}
@ -124,25 +132,13 @@ template<typename MultiPoint>
bool read_multi_point_WKT(std::istream& in,
MultiPoint& mp)
{
if(!in.good())
return false;
CGAL::internal::Geometry_container<MultiPoint, boost::geometry::multi_point_tag> gc(mp);
std::string line;
while(std::getline(in, line))
while(internal::get_a_new_line(in, line))
{
std::istringstream iss(line);
std::string type;
iss >> type;
if(type.substr(0, 10).compare("MULTIPOINT") == 0)
if(line.substr(0, 10).compare("MULTIPOINT") == 0)
{
try{
boost::geometry::read_wkt(line, gc);
} catch(...){
std::cerr << "error." << std::endl;
return false;
}
CGAL::internal::Geometry_container<MultiPoint, boost::geometry::multi_point_tag> gc(mp);
internal::read_wkt_or_fail_stream(in, line, gc);
break;
}
}
@ -170,25 +166,13 @@ template<typename LineString>
bool read_linestring_WKT(std::istream& in,
LineString& polyline)
{
if(!in.good())
return false;
CGAL::internal::Geometry_container<LineString, boost::geometry::linestring_tag> gc(polyline);
std::string line;
while(std::getline(in, line))
while(internal::get_a_new_line(in, line))
{
std::istringstream iss(line);
std::string type;
iss >> type;
if(type.substr(0, 10).compare("LINESTRING") == 0)
if(line.substr(0, 10).compare("LINESTRING") == 0)
{
try{
boost::geometry::read_wkt(line, gc);
} catch(...){
std::cerr << "error." << std::endl;
return false;
}
CGAL::internal::Geometry_container<LineString, boost::geometry::linestring_tag> gc(polyline);
internal::read_wkt_or_fail_stream(in, line, gc);
break;
}
}
@ -214,40 +198,26 @@ template<typename MultiLineString>
bool read_multi_linestring_WKT(std::istream& in,
MultiLineString& mls)
{
if(!in.good())
return false;
typedef typename MultiLineString::value_type PointRange;
typedef CGAL::internal::Geometry_container<PointRange, boost::geometry::linestring_tag> LineString;
std::string line;
while(internal::get_a_new_line(in, line))
{
if(line.substr(0, 15).compare("MULTILINESTRING") == 0)
{
using PointRange = typename MultiLineString::value_type;
using LineString = CGAL::internal::Geometry_container<PointRange, boost::geometry::linestring_tag>;
std::vector<LineString> pr_range;
CGAL::internal::Geometry_container<std::vector<LineString>, boost::geometry::multi_linestring_tag> gc(pr_range);
std::string line;
while(std::getline(in, line))
{
std::istringstream iss(line);
std::string type;
iss >> type;
if(type.substr(0, 15).compare("MULTILINESTRING") == 0)
{
try
{
boost::geometry::read_wkt(line, gc);
}
catch(...)
{
std::cerr << "error." << std::endl;
return false;
internal::read_wkt_or_fail_stream(in, line, gc);
for(LineString& ls : gc) {
mls.push_back(*ls.range);
}
break;
}
}
for(LineString& ls : gc)
mls.push_back(*ls.range);
return !in.fail();
}
@ -266,28 +236,12 @@ template<typename Polygon>
bool read_polygon_WKT(std::istream& in,
Polygon& polygon)
{
if(!in.good())
return false;
std::string line;
while(std::getline(in, line))
while(internal::get_a_new_line(in, line))
{
std::istringstream iss(line);
std::string type;
iss >> type;
if(type.substr(0, 7).compare("POLYGON") == 0)
if(line.substr(0, 7).compare("POLYGON") == 0)
{
try
{
boost::geometry::read_wkt(line, polygon);
}
catch( ...)
{
in.setstate(std::ios::failbit);
return false;
};
internal::read_wkt_or_fail_stream(in, line, polygon);
internal::pop_back_if_equal_to_front(polygon);
break;
}
@ -313,31 +267,16 @@ template<typename MultiPolygon>
bool read_multi_polygon_WKT(std::istream& in,
MultiPolygon& polygons)
{
if(!in.good())
return false;
CGAL::internal::Geometry_container<MultiPolygon, boost::geometry::multi_polygon_tag> gc(polygons);
std::string line;
while(std::getline(in, line))
while(internal::get_a_new_line(in, line))
{
std::istringstream iss(line);
std::string type;
iss >> type;
if(line.substr(0, 12).compare("MULTIPOLYGON") == 0)
{
CGAL::internal::Geometry_container<MultiPolygon, boost::geometry::multi_polygon_tag> gc(polygons);
internal::read_wkt_or_fail_stream(in, line, gc);
if(type.substr(0, 12).compare("MULTIPOLYGON") == 0)
{
try
{
boost::geometry::read_wkt(line, gc);
}
catch( ...)
{
in.setstate(std::ios::failbit);
return false;
};
for(typename CGAL::internal::Geometry_container<MultiPolygon, boost::geometry::multi_polygon_tag>::iterator it = gc.begin(); it != gc.end(); ++it)
internal::pop_back_if_equal_to_front(*it);
for(auto& p : gc)
internal::pop_back_if_equal_to_front(p);
break;
}
@ -517,17 +456,15 @@ bool read_WKT(std::istream& is,
MultiLineString& polylines,
MultiPolygon& polygons)
{
if(!is.good())
return false;
auto fail = [&is]() { is.clear(is.rdstate() | std::ios::failbit); return false; };
while(is.good() && !is.eof())
std::string line;
while(is >> std::ws && is.good() && std::getline(is, line))
{
typedef typename MultiPoint::value_type Point;
typedef typename MultiLineString::value_type LineString;
typedef typename MultiPolygon::value_type Polygon;
std::string line;
std::getline(is, line);
std::string::size_type header_end = line.find("("); // }
if(header_end == std::string::npos){
continue;
@ -549,42 +486,42 @@ bool read_WKT(std::istream& is,
if(type == "POINT")
{
Point p;
CGAL::IO::read_point_WKT(iss, p);
if(!IO::read_point_WKT(iss, p) ) return fail();
points.push_back(p);
}
else if(type == "LINESTRING")
{
LineString l;
CGAL::IO::read_linestring_WKT(iss, l);
polylines.push_back(l);
if(!IO::read_linestring_WKT(iss, l)) return fail();
polylines.push_back(std::move(l));
}
else if(type == "POLYGON")
{
Polygon p;
CGAL::IO::read_polygon_WKT(iss, p);
if(!IO::read_polygon_WKT(iss, p)) return fail();
if(!p.outer_boundary().is_empty())
polygons.push_back(p);
polygons.push_back(std::move(p));
}
else if(type == "MULTIPOINT")
{
MultiPoint mp;
CGAL::IO::read_multi_point_WKT(iss, mp);
if(!IO::read_multi_point_WKT(iss, mp)) return fail();
for(const Point& point : mp)
points.push_back(point);
}
else if(type == "MULTILINESTRING")
{
MultiLineString mls;
CGAL::IO::read_multi_linestring_WKT(iss, mls);
for(const LineString& ls : mls)
polylines.push_back(ls);
if(!IO::read_multi_linestring_WKT(iss, mls)) return fail();
for(LineString& ls : mls)
polylines.push_back(std::move(ls));
}
else if(type == "MULTIPOLYGON")
{
MultiPolygon mp;
CGAL::IO::read_multi_polygon_WKT(iss, mp);
for(const Polygon& poly : mp)
polygons.push_back(poly);
if(!IO::read_multi_polygon_WKT(iss, mp)) return fail();
for(Polygon& poly : mp)
polygons.push_back(std::move(poly));
}
}

View File

@ -46,20 +46,16 @@ struct Geometry_container{
typedef typename Range::size_type size_type;
typedef typename Range::value_type value_type;
std::shared_ptr<Range> range;
bool must_delete;
//
// Default constructor.
// Creates a new internal Range.
// De-allocate memory after usage.
Geometry_container():range(new Range()), must_delete(true)
{
}
Geometry_container() : range(std::make_shared<Range>()) {}
/*
Copy constructor.
Store a pointer to the given range.
Memory NOT de-allocated after usage.
*/
Geometry_container(Range& range)
:range(&range, Dummy_deleter()), must_delete(false){}
Geometry_container(Range& range) : range(&range, Dummy_deleter()) {}
iterator begin()
{ return range->begin(); }