diff --git a/Applications/DataExplorer/mainwindow.cpp b/Applications/DataExplorer/mainwindow.cpp index 61c7062a3493f636572cc3a486582d1d50b30945..8854e1d5e0ec424b950547c2a946a5567178b31d 100644 --- a/Applications/DataExplorer/mainwindow.cpp +++ b/Applications/DataExplorer/mainwindow.cpp @@ -426,15 +426,18 @@ void MainWindow::save() } else if (fi.suffix().toLower() == "geo") { - int const return_val = - FileIO::GMSHInterface::writeGeoFile(_project.getGEOObjects(), fileName.toStdString()); + std::vector<std::string> selected_geometries; + _project.getGEOObjects().getGeometryNames(selected_geometries); - if (return_val == 1) + GMSHInterface gmsh_io( + _project.getGEOObjects(), true, + FileIO::GMSH::MeshDensityAlgorithm::AdaptiveMeshDensity, + 0.05, 0.5, 2, selected_geometries); + gmsh_io.setPrecision(std::numeric_limits<double>::digits10); + bool const success = gmsh_io.writeToFile(fileName.toStdString()); + + if (!success) OGSError::box(" No geometry available\n to write to geo-file"); - else if (return_val == 2) - OGSError::box("Error merging geometries"); - else if (return_val == 3) - OGSError::box("Error writing geo-file."); } } @@ -898,16 +901,18 @@ void MainWindow::callGMSH(std::vector<std::string> & selectedGeometries, if (!fileName.isEmpty()) { if (param4 == -1) { // adaptive meshing selected - GMSHInterface gmsh_io(*(static_cast<GeoLib::GEOObjects*> (&_project.getGEOObjects())), true, - FileIO::GMSH::MeshDensityAlgorithm::AdaptiveMeshDensity, param2, param3, param1, - selectedGeometries); - gmsh_io.setPrecision(20); + GMSHInterface gmsh_io( + _project.getGEOObjects(), true, + FileIO::GMSH::MeshDensityAlgorithm::AdaptiveMeshDensity, + param2, param3, param1, selectedGeometries); + gmsh_io.setPrecision(std::numeric_limits<double>::digits10); gmsh_io.writeToFile(fileName.toStdString()); } else { // homogeneous meshing selected - GMSHInterface gmsh_io(*(static_cast<GeoLib::GEOObjects*> (&_project.getGEOObjects())), true, - FileIO::GMSH::MeshDensityAlgorithm::FixedMeshDensity, param4, param3, param1, - selectedGeometries); - gmsh_io.setPrecision(20); + GMSHInterface gmsh_io( + _project.getGEOObjects(), true, + FileIO::GMSH::MeshDensityAlgorithm::FixedMeshDensity, + param4, param3, param1, selectedGeometries); + gmsh_io.setPrecision(std::numeric_limits<double>::digits10); gmsh_io.writeToFile(fileName.toStdString()); } diff --git a/Applications/Utils/FileConverter/GMSH2OGS.cpp b/Applications/Utils/FileConverter/GMSH2OGS.cpp index 5c4bbacb11eed58f95acb265202eacdc2f80277f..5fbdaa41658af5fcf96bc778ba569cb509a57e7d 100644 --- a/Applications/Utils/FileConverter/GMSH2OGS.cpp +++ b/Applications/Utils/FileConverter/GMSH2OGS.cpp @@ -45,7 +45,7 @@ int main (int argc, char* argv[]) TCLAP::ValueArg<std::string> ogs_mesh_arg( "o", "out", - "filename for output mesh (if extension is msh, old OGS fileformat is written)", + "filename for output mesh (if extension is .msh, old OGS-5 fileformat is written, if extension is .vtu, a vtk unstructure grid file is written (OGS-6 mesh format))", true, "", "filename as string"); diff --git a/FileIO/GMSHInterface.cpp b/FileIO/GMSHInterface.cpp index 05b3780424654f35ed073c071e192227db67d122..e643159933babdb89667c148121a690bed4dd048 100644 --- a/FileIO/GMSHInterface.cpp +++ b/FileIO/GMSHInterface.cpp @@ -1,18 +1,10 @@ /** - * \file - * \author Thomas Fischer - * \date 2010-04-29 - * \brief Implementation of the GMSHInterface class. * * \copyright * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org) * Distributed under a Modified BSD License. * See accompanying file LICENSE.txt or * http://www.opengeosys.org/project/license - * - * @file GMSHInterface.cpp - * @date 2010-04-29 - * @author Thomas Fischer */ #include <fstream> @@ -35,7 +27,7 @@ #include "GeoLib/Polygon.h" #include "GeoLib/Polyline.h" #include "GeoLib/PolylineWithSegmentMarker.h" -#include "GeoLib/QuadTree.h" +#include "GeoLib/PolygonWithSegmentMarker.h" #include "MathLib/LinAlg/Solvers/GaussAlgorithm.h" @@ -46,14 +38,18 @@ namespace FileIO { -GMSHInterface::GMSHInterface(GeoLib::GEOObjects & geo_objs, +GMSHInterface::GMSHInterface(GeoLib::GEOObjects& geo_objs, bool /*include_stations_as_constraints*/, GMSH::MeshDensityAlgorithm mesh_density_algorithm, - double param1, - double param2, - std::size_t param3, - std::vector<std::string>& selected_geometries) : - _n_lines(0), _n_plane_sfc(0), _geo_objs(geo_objs), _selected_geometries(selected_geometries) + double param1, double param2, std::size_t param3, + std::vector<std::string>& selected_geometries, + bool rotate, bool keep_preprocessed_geometry) + : _n_lines(0), + _n_plane_sfc(0), + _geo_objs(geo_objs), + _selected_geometries(selected_geometries), + _rotate(rotate), + _keep_preprocessed_geometry(keep_preprocessed_geometry) { switch (mesh_density_algorithm) { case GMSH::MeshDensityAlgorithm::FixedMeshDensity: @@ -74,45 +70,6 @@ GMSHInterface::~GMSHInterface() delete polygon_tree; } -int GMSHInterface::writeGeoFile(GeoLib::GEOObjects &geo_objects, std::string const& file_name) -{ - std::vector<std::string> names; - geo_objects.getGeometryNames(names); - - if (names.empty()) - { - ERR ("No geometry information available."); - return 1; - } - - bool const multiple_geometries = (names.size() > 1); - std::string merge_name("MergedGeometry"); - if (multiple_geometries) - { - if (geo_objects.mergeGeometries (names, merge_name) != 1) - return 2; - names.clear(); - names.push_back(merge_name); - } - else - merge_name = names[0]; - - // default parameters for GMSH interface - double param1(0.5); // mesh density scaling on normal points - double param2(0.05); // mesh density scaling on station points - std::size_t param3(2); // points per leaf - GMSHInterface gmsh_io(geo_objects, true, FileIO::GMSH::MeshDensityAlgorithm::AdaptiveMeshDensity, param1, param2, param3, names); - int const writer_return_val = gmsh_io.writeToFile(file_name); - - if (multiple_geometries) - { - geo_objects.removeSurfaceVec(merge_name); - geo_objects.removePolylineVec(merge_name); - geo_objects.removePointVec(merge_name); - } - return (writer_return_val==1) ? 0 : 3; -} - bool GMSHInterface::isGMSHMeshFile(const std::string& fname) { std::ifstream input(fname.c_str()); @@ -288,14 +245,14 @@ GMSHInterface::readElement(std::ifstream &in, case 1: { readNodeIDs(in, 2, node_ids, id_map); // edge_nodes array will be deleted from Line object - MeshLib::Node** edge_nodes = new MeshLib::Node*[2]; + auto edge_nodes = new MeshLib::Node*[2]; edge_nodes[0] = nodes[node_ids[0]]; edge_nodes[1] = nodes[node_ids[1]]; return std::make_pair(new MeshLib::Line(edge_nodes), mat_id); } case 2: { readNodeIDs(in, 3, node_ids, id_map); - MeshLib::Node** tri_nodes = new MeshLib::Node*[3]; + auto tri_nodes = new MeshLib::Node*[3]; tri_nodes[0] = nodes[node_ids[2]]; tri_nodes[1] = nodes[node_ids[1]]; tri_nodes[2] = nodes[node_ids[0]]; @@ -303,35 +260,35 @@ GMSHInterface::readElement(std::ifstream &in, } case 3: { readNodeIDs(in, 4, node_ids, id_map); - MeshLib::Node** quad_nodes = new MeshLib::Node*[4]; + auto quad_nodes = new MeshLib::Node*[4]; for (unsigned k(0); k < 4; k++) quad_nodes[k] = nodes[node_ids[k]]; return std::make_pair(new MeshLib::Quad(quad_nodes), mat_id); } case 4: { readNodeIDs(in, 4, node_ids, id_map); - MeshLib::Node** tet_nodes = new MeshLib::Node*[5]; + auto tet_nodes = new MeshLib::Node*[5]; for (unsigned k(0); k < 4; k++) tet_nodes[k] = nodes[node_ids[k]]; return std::make_pair(new MeshLib::Tet(tet_nodes), mat_id); } case 5: { readNodeIDs(in, 8, node_ids, id_map); - MeshLib::Node** hex_nodes = new MeshLib::Node*[8]; + auto hex_nodes = new MeshLib::Node*[8]; for (unsigned k(0); k < 8; k++) hex_nodes[k] = nodes[node_ids[k]]; return std::make_pair(new MeshLib::Hex(hex_nodes), mat_id); } case 6: { readNodeIDs(in, 6, node_ids, id_map); - MeshLib::Node** prism_nodes = new MeshLib::Node*[6]; + auto prism_nodes = new MeshLib::Node*[6]; for (unsigned k(0); k < 6; k++) prism_nodes[k] = nodes[node_ids[k]]; return std::make_pair(new MeshLib::Prism(prism_nodes), mat_id); } case 7: { readNodeIDs(in, 5, node_ids, id_map); - MeshLib::Node** pyramid_nodes = new MeshLib::Node*[5]; + auto pyramid_nodes = new MeshLib::Node*[5]; for (unsigned k(0); k < 5; k++) pyramid_nodes[k] = nodes[node_ids[k]]; return std::make_pair(new MeshLib::Pyramid(pyramid_nodes), mat_id); @@ -355,54 +312,86 @@ bool GMSHInterface::write() #endif _out << "\n\n"; - writeGMSHInputFile(_out); - return true; + return writeGMSHInputFile(_out) <= 0; } -void GMSHInterface::writeGMSHInputFile(std::ostream& out) +int GMSHInterface::writeGMSHInputFile(std::ostream& out) { DBUG("GMSHInterface::writeGMSHInputFile(): get data from GEOObjects."); if (_selected_geometries.empty()) - return; + return 1; - bool remove_geometry(false); // *** get and merge data from _geo_objs if (_selected_geometries.size() > 1) { _gmsh_geo_name = "GMSHGeometry"; - remove_geometry = true; - _geo_objs.mergeGeometries(_selected_geometries, _gmsh_geo_name); + if (_geo_objs.mergeGeometries(_selected_geometries, _gmsh_geo_name)) + return 2; } else { _gmsh_geo_name = _selected_geometries[0]; - remove_geometry = false; + _keep_preprocessed_geometry = true; } - std::vector<GeoLib::Point*> * merged_pnts(const_cast<std::vector<GeoLib::Point*> *>(_geo_objs.getPointVec(_gmsh_geo_name))); + + std::vector<GeoLib::Point*>* merged_pnts( + const_cast<std::vector<GeoLib::Point*>*>( + _geo_objs.getPointVec(_gmsh_geo_name))); if (! merged_pnts) { ERR("GMSHInterface::writeGMSHInputFile(): Did not found any points."); - return; + return 2; } - // Rotate points to the x-y-plane. - _inverse_rot_mat = GeoLib::rotatePointsToXY(*merged_pnts); - // Compute inverse rotation matrix to reverse the rotation later on. - _inverse_rot_mat.transposeInPlace(); + if (_rotate) { + // Rotate points to the x-y-plane. + _inverse_rot_mat = GeoLib::rotatePointsToXY(*merged_pnts); + // Compute inverse rotation matrix to reverse the rotation later on. + _inverse_rot_mat.transposeInPlace(); + } else { + // project data on the x-y-plane + _inverse_rot_mat(0,0) = 1.0; + _inverse_rot_mat(1,1) = 1.0; + _inverse_rot_mat(2,2) = 1.0; + for (auto pnt : *merged_pnts) + (*pnt)[2] = 0.0; + } - std::vector<GeoLib::Polyline*> const* merged_plys(_geo_objs.getPolylineVec(_gmsh_geo_name)); + std::vector<GeoLib::Polyline*> const* merged_plys( + _geo_objs.getPolylineVec(_gmsh_geo_name)); DBUG("GMSHInterface::writeGMSHInputFile(): \t ok."); + if (!merged_plys) { + ERR("GMSHInterface::writeGMSHInputFile(): Did not find any polylines."); + return 2; + } + + // *** compute and insert all intersection points between polylines + GeoLib::PointVec& pnt_vec(*const_cast<GeoLib::PointVec*>( + _geo_objs.getPointVecObj(_gmsh_geo_name))); + GeoLib::computeAndInsertAllIntersectionPoints(pnt_vec, + *(const_cast<std::vector<GeoLib::Polyline*>*>(merged_plys))); + // *** compute topological hierarchy of polygons - if (merged_plys) { - for (std::vector<GeoLib::Polyline*>::const_iterator it(merged_plys->begin()); - it!=merged_plys->end(); ++it) { - if ((*it)->isClosed()) { - _polygon_tree_list.push_back(new GMSH::GMSHPolygonTree(new GeoLib::Polygon(*(*it), true), NULL, _geo_objs, _gmsh_geo_name, _mesh_density_strategy)); - } + for (auto polyline : *merged_plys) { + if (!polyline->isClosed()) { + continue; } - DBUG("GMSHInterface::writeGMSHInputFile(): Compute topological hierarchy - detected %d polygons.", _polygon_tree_list.size()); - GeoLib::createPolygonTrees<GMSH::GMSHPolygonTree>(_polygon_tree_list); - DBUG("GMSHInterface::writeGMSHInputFile(): Compute topological hierarchy - calculated %d polygon trees.", _polygon_tree_list.size()); - } else { - return; + _polygon_tree_list.push_back(new GMSH::GMSHPolygonTree( + new GeoLib::PolygonWithSegmentMarker(*polyline), nullptr, _geo_objs, + _gmsh_geo_name, _mesh_density_strategy)); + } + DBUG( + "GMSHInterface::writeGMSHInputFile(): Computed topological hierarchy - " + "detected %d polygons.", + _polygon_tree_list.size()); + GeoLib::createPolygonTrees<GMSH::GMSHPolygonTree>(_polygon_tree_list); + DBUG( + "GMSHInterface::writeGMSHInputFile(): Computed topological hierarchy - " + "calculated %d polygon trees.", + _polygon_tree_list.size()); + + // *** Mark in each polygon tree the segments shared by two polygons. + for (auto* polygon_tree : _polygon_tree_list) + { + polygon_tree->markSharedSegments(); } // *** insert stations and polylines (except polygons) in the appropriate object of @@ -426,25 +415,24 @@ void GMSHInterface::writeGMSHInputFile(std::ostream& out) } } } - std::string gmsh_stations_name(_gmsh_geo_name+"-Stations"); if (! gmsh_stations->empty()) { _geo_objs.addStationVec(std::move(gmsh_stations), gmsh_stations_name); } // *** insert polylines - const std::size_t n_plys(merged_plys->size()); - for (std::size_t k(0); k<n_plys; k++) { - if (! (*merged_plys)[k]->isClosed()) { - for (std::list<GMSH::GMSHPolygonTree*>::iterator it(_polygon_tree_list.begin()); - it != _polygon_tree_list.end(); ++it) { - (*it)->insertPolyline(new GeoLib::PolylineWithSegmentMarker(*(*merged_plys)[k])); + for (auto polyline : *merged_plys) { + if (!polyline->isClosed()) { + for (auto * polygon_tree : _polygon_tree_list) { + auto polyline_with_segment_marker = + new GeoLib::PolylineWithSegmentMarker(*polyline); + polygon_tree->insertPolyline(polyline_with_segment_marker); } } } // *** init mesh density strategies - for (std::list<GMSH::GMSHPolygonTree*>::iterator it(_polygon_tree_list.begin()); + for (auto it(_polygon_tree_list.begin()); it != _polygon_tree_list.end(); ++it) { (*it)->initMeshDensityStrategy(); } @@ -453,9 +441,9 @@ void GMSHInterface::writeGMSHInputFile(std::ostream& out) const std::size_t n_merged_pnts(merged_pnts->size()); _gmsh_pnts.resize(n_merged_pnts); for (std::size_t k(0); k<n_merged_pnts; k++) { - _gmsh_pnts[k] = NULL; + _gmsh_pnts[k] = nullptr; } - for (std::list<GMSH::GMSHPolygonTree*>::iterator it(_polygon_tree_list.begin()); + for (auto it(_polygon_tree_list.begin()); it != _polygon_tree_list.end(); ++it) { (*it)->createGMSHPoints(_gmsh_pnts); } @@ -463,21 +451,23 @@ void GMSHInterface::writeGMSHInputFile(std::ostream& out) // *** finally write data :-) writePoints(out); std::size_t pnt_id_offset(_gmsh_pnts.size()); - for (std::list<GMSH::GMSHPolygonTree*>::iterator it(_polygon_tree_list.begin()); - it != _polygon_tree_list.end(); ++it) { - (*it)->writeLineLoop(_n_lines, _n_plane_sfc, out); - (*it)->writeSubPolygonsAsLineConstraints(_n_lines, _n_plane_sfc-1, out); - (*it)->writeLineConstraints(_n_lines, _n_plane_sfc-1, out); - (*it)->writeStations(pnt_id_offset, _n_plane_sfc-1, out); - (*it)->writeAdditionalPointData(pnt_id_offset, _n_plane_sfc-1, out); + for (auto* polygon_tree : _polygon_tree_list) + { + polygon_tree->writeLineLoop(_n_lines, _n_plane_sfc, out); + polygon_tree->writeSubPolygonsAsLineConstraints(_n_lines, _n_plane_sfc-1, out); + polygon_tree->writeLineConstraints(_n_lines, _n_plane_sfc-1, out); + polygon_tree->writeStations(pnt_id_offset, _n_plane_sfc-1, out); + polygon_tree->writeAdditionalPointData(pnt_id_offset, _n_plane_sfc-1, out); } - if (remove_geometry) { + if (! _keep_preprocessed_geometry) { _geo_objs.removeSurfaceVec(_gmsh_geo_name); _geo_objs.removePolylineVec(_gmsh_geo_name); _geo_objs.removePointVec(_gmsh_geo_name); _geo_objs.removeStationVec(gmsh_stations_name); } + + return 0; } void GMSHInterface::writePoints(std::ostream& out) const diff --git a/FileIO/GMSHInterface.h b/FileIO/GMSHInterface.h index f6132ff89a0abec6d700363d3f3663bc61970469..78bc53ca0b15d5af78dd13fd9a27a1a09ab415f2 100644 --- a/FileIO/GMSHInterface.h +++ b/FileIO/GMSHInterface.h @@ -54,27 +54,40 @@ enum class MeshDensityAlgorithm { /** * \brief Reads and writes GMSH-files to and from OGS data structures. */ -class GMSHInterface : public BaseLib::IO::Writer +class GMSHInterface final : public BaseLib::IO::Writer { public: - /** - * - * @param geo_objs reference tp instance of class GEOObject that maintains the geometries. - * The instance is used for preparation geometries for writing them to the gmsh file format. - * @param include_stations_as_constraints switch to enable writing stations as constraints - * @param mesh_density_algorithm one of the mesh density algorithms (\@see enum MeshDensityAlgorithm) + * @param geo_objs reference to instance of class GEOObject that maintains + * the geometries. + * The instance is used for preparation geometries for writing them to + * the gmsh file format. + * @param include_stations_as_constraints switch to enable writing stations + * as constraints + * @param mesh_density_algorithm one of the mesh density algorithms (\@see + * enum MeshDensityAlgorithm) * @param param1 parameter that can be used for the mesh density algorithm * @param param2 parameter that can be used for the mesh density algorithm * @param param3 parameter that can be used for the mesh density algorithm - * @param selected_geometries vector of names of geometries, that should be employed for mesh generation. - * @return + * @param selected_geometries vector of names of geometries, that should be + * employed for mesh generation. + * @param rotate if the value of the parameter is true then the input points + * will be rotated on the \f$x\f$-\f$y\f$-plane, else the input points will + * be (orthogonal) projected to the \f$x\f$-\f$y\f$-plane. + * @param keep_preprocessed_geometry keep the pre-processed geometry, useful + * for debugging the mesh creation */ - GMSHInterface (GeoLib::GEOObjects & geo_objs, - bool include_stations_as_constraints, - GMSH::MeshDensityAlgorithm mesh_density_algorithm, - double param1, double param2, std::size_t param3, - std::vector<std::string> & selected_geometries); + GMSHInterface(GeoLib::GEOObjects& geo_objs, + bool include_stations_as_constraints, + GMSH::MeshDensityAlgorithm mesh_density_algorithm, + double param1, double param2, std::size_t param3, + std::vector<std::string>& selected_geometries, + bool rotate = false, bool keep_preprocessed_geometry = false); + + GMSHInterface(GMSHInterface const&) = delete; + GMSHInterface(GMSHInterface &&) = delete; + GMSHInterface& operator=(GMSHInterface const&) = delete; + GMSHInterface& operator=(GMSHInterface &&) = delete; ~GMSHInterface(); @@ -91,20 +104,13 @@ public: */ static MeshLib::Mesh* readGMSHMesh (std::string const& fname); - /** - * Export script for writing geo files. - * To do this, all geometries currently loaded are merged, the merged result is written to a - * file and then the merged geometry is removed again. - * @return error code, i.e. 0 = okay, 1 = geo_objects is empty, 2 = error while merging, 3 = error writing file - */ - static int writeGeoFile(GeoLib::GEOObjects &geo_objects, std::string const& file_name); - protected: bool write(); private: /// Reads a mesh element from the input stream - static std::pair<MeshLib::Element*, int> readElement(std::ifstream &in, + static std::pair<MeshLib::Element*, int> readElement( + std::ifstream& in, std::vector<MeshLib::Node*> const& nodes, std::map<unsigned, unsigned> const& id_map); @@ -112,10 +118,15 @@ private: * 1. get and merge data from _geo_objs * 2. compute topological hierarchy * @param out + * @todo activate error codes and hand them on to the Writer class, + * i.e. 0 = okay, 1 = geo_objects is empty, 2 = error while merging, + * 3 = error writing file */ - void writeGMSHInputFile(std::ostream & out); + int writeGMSHInputFile(std::ostream & out); - static void readNodeIDs(std::ifstream &in, unsigned n_nodes, std::vector<unsigned> &node_ids, std::map<unsigned, unsigned> const& id_map); + static void readNodeIDs(std::ifstream& in, unsigned n_nodes, + std::vector<unsigned>& node_ids, + std::map<unsigned, unsigned> const& id_map); void writePoints(std::ostream& out) const; @@ -132,7 +143,12 @@ private: GMSH::GMSHMeshDensityStrategy *_mesh_density_strategy; /// Holds the inverse rotation matrix. The matrix is used in writePoints() to /// revert the rotation done in writeGMSHInputFile(). - MathLib::DenseMatrix<double> _inverse_rot_mat = MathLib::DenseMatrix<double>(3,3); + MathLib::DenseMatrix<double> _inverse_rot_mat = + MathLib::DenseMatrix<double>(3, 3, 0); + /// Signals if the input points should be rotated or projected to the + /// \f$x\f$-\f$y\f$-plane + bool _rotate = false; + bool _keep_preprocessed_geometry = true; }; } diff --git a/FileIO/GmshIO/GMSHPolygonTree.cpp b/FileIO/GmshIO/GMSHPolygonTree.cpp index 8f3a92f966a5b32e37fbef9fe9b7340dc2d96fcc..be35d891e14795e569229e9b61081c852c508927 100644 --- a/FileIO/GmshIO/GMSHPolygonTree.cpp +++ b/FileIO/GmshIO/GMSHPolygonTree.cpp @@ -17,16 +17,19 @@ #include "GMSHFixedMeshDensity.h" #include "GMSHAdaptiveMeshDensity.h" +#include "GeoLib/AnalyticalGeometry.h" #include "GeoLib/GEOObjects.h" #include "GeoLib/Point.h" #include "GeoLib/Polygon.h" #include "GeoLib/PolylineWithSegmentMarker.h" +#include "GeoLib/PolygonWithSegmentMarker.h" namespace FileIO { namespace GMSH { -GMSHPolygonTree::GMSHPolygonTree(GeoLib::Polygon* polygon, GMSHPolygonTree* parent, +GMSHPolygonTree::GMSHPolygonTree(GeoLib::PolygonWithSegmentMarker* polygon, + GMSHPolygonTree* parent, GeoLib::GEOObjects &geo_objs, std::string const& geo_name, GMSHMeshDensityStrategy * mesh_density_strategy) : GeoLib::SimplePolygonTree(polygon, parent), _geo_objs(geo_objs), _geo_name(geo_name), @@ -45,6 +48,25 @@ GMSHPolygonTree::~GMSHPolygonTree() delete _node_polygon; } +void GMSHPolygonTree::markSharedSegments() +{ + if (_children.empty()) + return; + + if (_parent == nullptr) + return; + + for (auto it(_children.begin()); it != _children.end(); it++) { + std::size_t const n_pnts((*it)->getPolygon()->getNumberOfPoints()); + for (std::size_t k(1); k<n_pnts; k++) { + if (GeoLib::containsEdge(*(_parent->getPolygon()), + _node_polygon->getPointID(k-1), + _node_polygon->getPointID(k))) + static_cast<GeoLib::PolygonWithSegmentMarker*>(_node_polygon)->markSegment(k, true); + } + } +} + bool GMSHPolygonTree::insertStation(GeoLib::Point const* station) { if (_node_polygon->isPntInPolygon(*station)) { @@ -67,80 +89,134 @@ bool GMSHPolygonTree::insertStation(GeoLib::Point const* station) } } -void GMSHPolygonTree::insertPolyline (GeoLib::PolylineWithSegmentMarker * ply) +void GMSHPolygonTree::insertPolyline(GeoLib::PolylineWithSegmentMarker * ply) { - if (_node_polygon->isPartOfPolylineInPolygon(*ply)) { - // check children - for (std::list<SimplePolygonTree*>::const_iterator it (_children.begin()); - it != _children.end(); ++it) { - dynamic_cast<GMSHPolygonTree*>((*it))->insertPolyline (ply); + if (!_node_polygon->isPartOfPolylineInPolygon(*ply)) + return; + + // check if polyline segments are inside of the polygon, intersect the + // polygon or are part of the boundary of the polygon + for (auto * polygon_tree : _children) { + dynamic_cast<GMSHPolygonTree*>(polygon_tree)->insertPolyline(ply); + } + + // calculate possible intersection points between the node polygon + // (_node_polygon) and the given polyline ply + // pay attention: loop bound is not fix! + GeoLib::Point tmp_pnt; + GeoLib::PointVec & pnt_vec(*(_geo_objs.getPointVecObj(_geo_name))); + for (auto segment_it(ply->begin()); segment_it != ply->end(); + ++segment_it) + { + if (ply->isSegmentMarked(segment_it.getSegmentNumber())) + continue; + + if (_node_polygon->containsSegment(*segment_it)) { + ply->markSegment(segment_it.getSegmentNumber(), true); + continue; } - _plys.push_back(ply); - // calculate possible intersection points - // pay attention: loop bound is not fix! - std::size_t n_segments (ply->getNumberOfPoints()-1); - GeoLib::Point tmp_pnt; - GeoLib::PointVec & pnt_vec(*(_geo_objs.getPointVecObj(_geo_name))); - for (std::size_t k(0); k<n_segments; k++) { - if (! ply->isSegmentMarked(k)) { - std::size_t seg_num(0); - GeoLib::Point *intersection_pnt(new GeoLib::Point); - while (_node_polygon->getNextIntersectionPointPolygonLine( - {const_cast<GeoLib::Point*>(ply->getPoint(k)), - const_cast<GeoLib::Point*>(ply->getPoint(k + 1))}, - *intersection_pnt, seg_num)) - { - // insert the intersection point to point vector of GEOObjects instance - const std::size_t pnt_vec_size(pnt_vec.size()); - // appendPoints deletes an already existing point - const std::size_t pnt_id(pnt_vec.push_back(intersection_pnt)); - if (pnt_vec_size < pnt_vec.size()) { // case: new point - // modify the polygon - _node_polygon->insertPoint(seg_num+1, pnt_id); - // modify the polyline - ply->insertPoint(k+1, pnt_id); - n_segments++; - } else { // case: existing point - // check if point id is within the polygon - if (! _node_polygon->isPointIDInPolyline(pnt_id)) { - _node_polygon->insertPoint(seg_num+1, pnt_id); - } - // check if point id is in polyline - if (! ply->isPointIDInPolyline(pnt_id)) { - ply->insertPoint(k+1, pnt_id); - n_segments++; - } - } + std::size_t seg_num(0); + GeoLib::Point intersection_pnt; + while (_node_polygon->getNextIntersectionPointPolygonLine( + *segment_it, intersection_pnt, seg_num)) + { + // insert the intersection point to point vector of GEOObjects instance + const std::size_t pnt_vec_size(pnt_vec.size()); + std::size_t pnt_id( + pnt_vec.push_back(new GeoLib::Point(intersection_pnt))); + if (pnt_vec_size < pnt_vec.size()) { // case: new point + // modify the polygon + _node_polygon->insertPoint(seg_num+1, pnt_id); + // modify the polyline + ply->insertPoint(segment_it.getSegmentNumber(), pnt_id); + } else { // case: existing point + // check if point id is within the polygon + if (! _node_polygon->isPointIDInPolyline(pnt_id)) { + _node_polygon->insertPoint(seg_num+1, pnt_id); + } - std::size_t tmp_seg_num(seg_num+1); - if (!_node_polygon->getNextIntersectionPointPolygonLine( - {const_cast<GeoLib::Point*>(ply->getPoint(k)), - const_cast<GeoLib::Point*>(ply->getPoint(k + 1))}, - tmp_pnt, tmp_seg_num)) - { - // check a point of the segment except the end points - for (std::size_t i(0); i<3; i++) { - tmp_pnt[i] = ((*(ply->getPoint(k)))[i] + (*(ply->getPoint(k+1)))[i]) / 2; - } - if (_node_polygon->isPntInPolygon(tmp_pnt)) { - ply->markSegment(k, true); - // insert line segment as constraint - _gmsh_lines_for_constraints.push_back(new GMSHLine(ply->getPointID(k), ply->getPointID(k+1))); - } - } - intersection_pnt = new GeoLib::Point; - seg_num++; + // check if point id is in polyline + if (! ply->isPointIDInPolyline(pnt_id)) { + ply->insertPoint(segment_it.getSegmentNumber()+1, pnt_id); } + } + std::size_t tmp_seg_num(seg_num+1); + if (!_node_polygon->getNextIntersectionPointPolygonLine( + *segment_it, tmp_pnt, tmp_seg_num)) + { // check a point of the segment except the end points for (std::size_t i(0); i<3; i++) { - tmp_pnt[i] = ((*(ply->getPoint(k)))[i] + (*(ply->getPoint(k+1)))[i]) / 2; + tmp_pnt[i] = ((*segment_it).getBeginPoint()[i] + + (*segment_it).getEndPoint()[i]) / + 2; } if (_node_polygon->isPntInPolygon(tmp_pnt)) { - ply->markSegment(k, true); + ply->markSegment(segment_it.getSegmentNumber(), true); // insert line segment as constraint - _gmsh_lines_for_constraints.push_back(new GMSHLine(ply->getPointID(k), ply->getPointID(k+1))); + _gmsh_lines_for_constraints.push_back( + new GMSHLine((*segment_it).getBeginPoint().getID(), + (*segment_it).getEndPoint().getID())); + } + } + seg_num++; + + // check a point of the segment except the end points + for (std::size_t i(0); i<3; i++) { + tmp_pnt[i] = ((*segment_it).getBeginPoint()[i] + + (*segment_it).getEndPoint()[i]) / + 2; + } + + checkIntersectionsSegmentExistingPolylines(ply, segment_it); + + if (_node_polygon->isPntInPolygon(tmp_pnt)) { + ply->markSegment(segment_it.getSegmentNumber(), true); + // insert line segment as constraint + _gmsh_lines_for_constraints.push_back( + new GMSHLine((*segment_it).getBeginPoint().getID(), + (*segment_it).getEndPoint().getID())); + } + } + } + + _plys.push_back(ply); +} + +void GMSHPolygonTree::checkIntersectionsSegmentExistingPolylines( + GeoLib::PolylineWithSegmentMarker* ply, + GeoLib::Polyline::SegmentIterator const& seg_it) +{ + std::size_t const ply_segment_number(seg_it.getSegmentNumber()); + for(GeoLib::PolylineWithSegmentMarker *const p : _plys) { + std::size_t n_segments(p->getNumberOfSegments()); + GeoLib::PointVec & pnt_vec(*(_geo_objs.getPointVecObj(_geo_name))); + for (auto seg_it_p(p->begin()); seg_it_p != p->end(); ++seg_it_p) { + GeoLib::Point s; // intersection point + if (GeoLib::lineSegmentIntersect(*seg_it, *seg_it_p, s)) + { + const std::size_t pnt_vec_size(pnt_vec.size()); + // point id of new point in GEOObjects instance + const std::size_t pnt_id(pnt_vec.push_back(new GeoLib::Point(s))); + if (pnt_vec_size < pnt_vec.size()) { // case: new point + // modify polyline already in this node + p->insertPoint(seg_it_p.getSegmentNumber()+1, pnt_id); + n_segments++; + // modify polyline + ply->insertPoint(ply_segment_number+1, pnt_id); + } else { // case: point exists already in geometry + // check if point is not alread in polyline p + std::size_t const k(seg_it_p.getSegmentNumber()); + if (p->getPointID(k) != pnt_id && p->getPointID(k+1) != pnt_id) { + p->insertPoint(k+1, pnt_id); + n_segments++; + } + // check if point is not already in polyline ply + if (ply->getPointID(ply_segment_number) != pnt_id + && ply->getPointID(ply_segment_number+1) != pnt_id) { + ply->insertPoint(ply_segment_number+1, pnt_id); + } } } } @@ -179,10 +255,14 @@ void GMSHPolygonTree::initMeshDensityStrategy() void GMSHPolygonTree::createGMSHPoints(std::vector<FileIO::GMSH::GMSHPoint*> & gmsh_pnts) const { const std::size_t n_pnts_polygon (_node_polygon->getNumberOfPoints()); - for (std::size_t k(0); k<n_pnts_polygon; k++) { + for (std::size_t k(0); k<n_pnts_polygon-1; k++) { const std::size_t id (_node_polygon->getPointID(k)); GeoLib::Point const*const pnt(_node_polygon->getPoint(k)); - gmsh_pnts[id] = new GMSHPoint(*pnt, id, _mesh_density_strategy->getMeshDensityAtPoint(pnt)); + // if this point was already part of another polyline + if (gmsh_pnts[id] != nullptr) + continue; + gmsh_pnts[id] = new GMSHPoint( + *pnt, id, _mesh_density_strategy->getMeshDensityAtPoint(pnt)); } const std::size_t n_plys(_plys.size()); @@ -191,8 +271,13 @@ void GMSHPolygonTree::createGMSHPoints(std::vector<FileIO::GMSH::GMSHPoint*> & g for (std::size_t j(0); j<n_pnts_in_ply; j++) { if (_node_polygon->isPntInPolygon(*(_plys[k]->getPoint(j)))) { const std::size_t id (_plys[k]->getPointID(j)); + // if this point was already part of another polyline + if (gmsh_pnts[id] != nullptr) + continue; GeoLib::Point const*const pnt(_plys[k]->getPoint(j)); - gmsh_pnts[id] = new GMSHPoint(*pnt, id, _mesh_density_strategy->getMeshDensityAtPoint(pnt)); + gmsh_pnts[id] = new GMSHPoint( + *pnt, id, + _mesh_density_strategy->getMeshDensityAtPoint(pnt)); } } } @@ -222,17 +307,25 @@ void GMSHPolygonTree::writeLineLoop(std::size_t &line_offset, std::size_t &sfc_o sfc_offset++; } -void GMSHPolygonTree::writeLineConstraints(std::size_t &line_offset, std::size_t sfc_number, std::ostream& out) const +void GMSHPolygonTree::writeLineConstraints(std::size_t& line_offset, + std::size_t sfc_number, + std::ostream& out) const { - const std::size_t n_plys (_plys.size()); - for (std::size_t j(0); j<n_plys; j++) { - const std::size_t n_pnts(_plys[j]->getNumberOfPoints()); - std::size_t first_pnt_id(_plys[j]->getPointID(0)), second_pnt_id; - for (std::size_t k(1); k<n_pnts; k++) { - second_pnt_id = _plys[j]->getPointID(k); - if (_plys[j]->isSegmentMarked(k-1) && _node_polygon->isPntInPolygon(*(_plys[j]->getPoint(k)))) { - out << "Line(" << line_offset + k-1 << ") = {" << first_pnt_id << "," << second_pnt_id << "};\n"; - out << "Line { " << line_offset+k-1 << " } In Surface { " << sfc_number << " };\n"; + for (auto polyline : _plys) + { + const std::size_t n_pnts(polyline->getNumberOfPoints()); + std::size_t first_pnt_id(polyline->getPointID(0)), second_pnt_id; + for (std::size_t k(1); k < n_pnts; k++) + { + second_pnt_id = polyline->getPointID(k); + if (polyline->isSegmentMarked(k - 1) && + _node_polygon->isPntInPolygon(*(polyline->getPoint(k))) && + !GeoLib::containsEdge(*_node_polygon, first_pnt_id, second_pnt_id)) + { + out << "Line(" << line_offset + k - 1 << ") = {" << first_pnt_id + << "," << second_pnt_id << "};\n"; + out << "Line { " << line_offset + k - 1 << " } In Surface { " + << sfc_number << " };\n"; } first_pnt_id = second_pnt_id; } @@ -313,11 +406,6 @@ void GMSHPolygonTree::writeAdditionalPointData(std::size_t & pnt_id_offset, std: void GMSHPolygonTree::getPointsFromSubPolygons(std::vector<GeoLib::Point const*>& pnts) { - const std::size_t n_pnts_polygon (_node_polygon->getNumberOfPoints()); - for (std::size_t k(0); k<n_pnts_polygon; k++) { - pnts.push_back(_node_polygon->getPoint(k)); - } - for (std::list<SimplePolygonTree*>::const_iterator it (_children.begin()); it != _children.end(); ++it) { dynamic_cast<GMSHPolygonTree*>((*it))->getPointsFromSubPolygons(pnts); } diff --git a/FileIO/GmshIO/GMSHPolygonTree.h b/FileIO/GmshIO/GMSHPolygonTree.h index b66d3a54e1bb2f0b26065a3dc445232aaadc5873..b234fbb64e51dfe3a1d62898d49d189efb39a6de 100644 --- a/FileIO/GmshIO/GMSHPolygonTree.h +++ b/FileIO/GmshIO/GMSHPolygonTree.h @@ -1,7 +1,7 @@ /** * \file * \author Thomas Fischer - * \date Mar 27m 2012 + * \date Mar 27 2012 * \brief Definition of the GMSHPolygonTree class. * * \copyright @@ -29,6 +29,7 @@ namespace GeoLib class GEOObjects; class Polygon; class PolylineWithSegmentMarker; + class PolygonWithSegmentMarker; } namespace FileIO @@ -37,11 +38,14 @@ namespace GMSH { class GMSHPolygonTree: public GeoLib::SimplePolygonTree { public: - GMSHPolygonTree(GeoLib::Polygon* polygon, GMSHPolygonTree * parent, + GMSHPolygonTree(GeoLib::PolygonWithSegmentMarker* polygon, GMSHPolygonTree * parent, GeoLib::GEOObjects &geo_objs, std::string const& geo_name, GMSHMeshDensityStrategy * mesh_density_strategy); virtual ~GMSHPolygonTree(); + /** Mark the segments shared by several polygons. */ + void markSharedSegments(); + /** * If the station point is inside the polygon, the method inserts the station into * the internal vector of stations. This method works recursive! @@ -86,6 +90,9 @@ public: private: void getPointsFromSubPolygons(std::vector<GeoLib::Point const*>& pnts); void getStationsInsideSubPolygons(std::vector<GeoLib::Point const*>& stations); + void checkIntersectionsSegmentExistingPolylines( + GeoLib::PolylineWithSegmentMarker* ply, + GeoLib::Polyline::SegmentIterator const& segment_iterator); GeoLib::GEOObjects & _geo_objs; std::string const& _geo_name; diff --git a/GeoLib/PolygonWithSegmentMarker.cpp b/GeoLib/PolygonWithSegmentMarker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d13b899237e6d3f03eb014cee56be8648974b9d3 --- /dev/null +++ b/GeoLib/PolygonWithSegmentMarker.cpp @@ -0,0 +1,48 @@ +/** + * + * \copyright + * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + */ + +#include "PolygonWithSegmentMarker.h" + +namespace GeoLib { +PolygonWithSegmentMarker::PolygonWithSegmentMarker( + GeoLib::Polyline const& polyline) + : GeoLib::Polygon(polyline, true), + _marker(polyline.getNumberOfPoints(), false) +{ +} + +void PolygonWithSegmentMarker::markSegment(std::size_t seg_num, bool mark_val) +{ + _marker[seg_num] = mark_val; +} + +bool PolygonWithSegmentMarker::isSegmentMarked(std::size_t seg_num) const +{ + return _marker[seg_num]; +} + +bool PolygonWithSegmentMarker::addPoint(std::size_t pnt_id) +{ + if (Polyline::addPoint(pnt_id)) { + _marker.push_back(false); + return true; + } + return false; +} + +bool PolygonWithSegmentMarker::insertPoint(std::size_t pos, std::size_t pnt_id) +{ + if (Polyline::insertPoint(pos, pnt_id)) { + _marker.insert(_marker.begin()+pos, _marker[pos]); + return true; + } + return false; +} + +} // end GeoLib diff --git a/GeoLib/PolygonWithSegmentMarker.h b/GeoLib/PolygonWithSegmentMarker.h new file mode 100644 index 0000000000000000000000000000000000000000..d6462d9850e14548a2fe9268154ff78a9c1cd47e --- /dev/null +++ b/GeoLib/PolygonWithSegmentMarker.h @@ -0,0 +1,57 @@ +/** + * + * \copyright + * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef POLYGONWITHSEGMENTMARKER_H_ +#define POLYGONWITHSEGMENTMARKER_H_ + +#include "Polygon.h" + +namespace GeoLib { + +class PolygonWithSegmentMarker final : public GeoLib::Polygon +{ +public: + explicit PolygonWithSegmentMarker(GeoLib::Polyline const& polyline); + + /** + * Method marks the segment (default mark is true). + * @param seg_num the segment number that should be marked + * @param mark_val the value of the flag (true or false) + */ + void markSegment(std::size_t seg_num, bool mark_val = true); + + /** + * Method returns the value of the mark for the given segment. + * @param seg_num segment number + * @return either true if the segment is marked or false else + */ + bool isSegmentMarked(std::size_t seg_num) const; + + /** + * Method calls @see Polyline::addPoint() and initializes the mark of the + * corresponding line segment. + * @see Polyline::addPoint() + */ + virtual bool addPoint(std::size_t pnt_id) override; + + /** + * Method calls the @see Polyline::insertPoint() and initializes the inserted line + * segment with the same value the previous line segment had. + * @see Polyline::insertPoint() + */ + virtual bool insertPoint(std::size_t pos, std::size_t pnt_id) override; + +private: + std::vector<bool> _marker; +}; + +} // end namespace GeoLib + +#endif /* POLYGONWITHSEGMENTMARKER_H_ */ diff --git a/GeoLib/Polyline.cpp b/GeoLib/Polyline.cpp index 683df570d881651ec3a0675e9bec0bc4c68b31d1..c00836551df11e2f21e1238230596e7d88bf40eb 100644 --- a/GeoLib/Polyline.cpp +++ b/GeoLib/Polyline.cpp @@ -421,7 +421,7 @@ double Polyline::getDistanceAlongPolyline(const MathLib::Point3d& pnt, double dist(-1.0), lambda; bool found = false; // loop over all line segments of the polyline - for (std::size_t k = 0; k < getNumberOfPoints() - 1; k++) { + for (std::size_t k = 0; k < getNumberOfSegments(); k++) { // is the orthogonal projection of the j-th node to the // line g(lambda) = _ply->getPoint(k) + lambda * (_ply->getPoint(k+1) - _ply->getPoint(k)) // at the k-th line segment of the polyline, i.e. 0 <= lambda <= 1? diff --git a/GeoLib/Polyline.h b/GeoLib/Polyline.h index 3de05b06663b3d5d632f13f9961c97bb676aa74e..83cbf53ea5e8d8d8644421eba13851adcc8e2564 100644 --- a/GeoLib/Polyline.h +++ b/GeoLib/Polyline.h @@ -118,7 +118,7 @@ public: * addition of the point would result in empty line segment \c false is * returned. */ - bool addPoint(std::size_t pnt_id); + virtual bool addPoint(std::size_t pnt_id); /** * Method inserts a new point (that have to be inside the _ply_pnts vector) @@ -131,7 +131,7 @@ public: * @return true if the point could be inserted, else false (if empty line * segments would be created). */ - bool insertPoint(std::size_t pos, std::size_t pnt_id); + virtual bool insertPoint(std::size_t pos, std::size_t pnt_id); /** * Method removes a point from the polyline. The connecting line segments will diff --git a/GeoLib/PolylineWithSegmentMarker.cpp b/GeoLib/PolylineWithSegmentMarker.cpp index 51a6929037aef4387d6daa6f0738a7eaa75a9a75..f770e7e91fb8a34d83640de2401b8b558e6af38c 100644 --- a/GeoLib/PolylineWithSegmentMarker.cpp +++ b/GeoLib/PolylineWithSegmentMarker.cpp @@ -15,40 +15,38 @@ #include "PolylineWithSegmentMarker.h" namespace GeoLib { - -PolylineWithSegmentMarker::PolylineWithSegmentMarker(GeoLib::Polyline const& polyline) - : GeoLib::Polyline(polyline) +PolylineWithSegmentMarker::PolylineWithSegmentMarker( + GeoLib::Polyline const& polyline) + : GeoLib::Polyline(polyline), _marker(polyline.getNumberOfSegments(), false) { - const std::size_t n_pnts(getNumberOfPoints()); - _marker.resize(n_pnts); - for (std::size_t k(0); k<n_pnts; k++) { - _marker[k] = false; - } } -PolylineWithSegmentMarker::~PolylineWithSegmentMarker() -{} - - void PolylineWithSegmentMarker::markSegment(std::size_t seg_num, bool mark_val) { _marker[seg_num] = mark_val; } + bool PolylineWithSegmentMarker::isSegmentMarked(std::size_t seg_num) const { return _marker[seg_num]; } -void PolylineWithSegmentMarker::addPoint(std::size_t pnt_id) +bool PolylineWithSegmentMarker::addPoint(std::size_t pnt_id) { - Polyline::addPoint(pnt_id); - _marker.push_back(false); + if (Polyline::addPoint(pnt_id)) { + _marker.push_back(false); + return true; + } + return false; } -void PolylineWithSegmentMarker::insertPoint(std::size_t pos, std::size_t pnt_id) +bool PolylineWithSegmentMarker::insertPoint(std::size_t pos, std::size_t pnt_id) { - Polyline::insertPoint(pos, pnt_id); - _marker.insert(_marker.begin()+pos, _marker[pos]); + if (Polyline::insertPoint(pos, pnt_id)) { + _marker.insert(_marker.begin()+pos, _marker[pos]); + return true; + } + return false; } } // end GeoLib diff --git a/GeoLib/PolylineWithSegmentMarker.h b/GeoLib/PolylineWithSegmentMarker.h index 8f58d1d199dcb4e80b829a4afff1c94c6176f21c..ca1b58be8a68373b582d634ae8308fd915bfe8c4 100644 --- a/GeoLib/PolylineWithSegmentMarker.h +++ b/GeoLib/PolylineWithSegmentMarker.h @@ -23,10 +23,10 @@ namespace GeoLib { * This is a polyline with the possibility to mark some segments. Thus class * PolylineWithSegmentMarker is derived from class Polyline. */ -class PolylineWithSegmentMarker: public GeoLib::Polyline { +class PolylineWithSegmentMarker final : public GeoLib::Polyline { public: - PolylineWithSegmentMarker(GeoLib::Polyline const& polyline); - virtual ~PolylineWithSegmentMarker(); + explicit PolylineWithSegmentMarker(GeoLib::Polyline const& polyline); + /** * Method marks the segment (default mark is true). * @param seg_num the segment number that should be marked @@ -45,14 +45,14 @@ public: * corresponding line segment. * @see Polyline::addPoint() */ - virtual void addPoint(std::size_t pnt_id); + virtual bool addPoint(std::size_t pnt_id) override; /** * Method calls the @see Polyline::insertPoint() and initializes the inserted line segment with the same * value the previous line segment had. * @see Polyline::insertPoint() */ - virtual void insertPoint(std::size_t pos, std::size_t pnt_id); + virtual bool insertPoint(std::size_t pos, std::size_t pnt_id) override; private: std::vector<bool> _marker;