BambuStudio/libslic3r/Geometry/Voronoi.hpp

196 lines
8.9 KiB
C++
Raw Permalink Normal View History

2024-12-20 06:44:50 +00:00
#ifndef slic3r_Geometry_Voronoi_hpp_
#define slic3r_Geometry_Voronoi_hpp_
#include "../Line.hpp"
#include "../Polyline.hpp"
#ifdef _MSC_VER
// Suppress warning C4146 in OpenVDB: unary minus operator applied to unsigned type, result still unsigned
#pragma warning(push)
#pragma warning(disable : 4146)
#endif // _MSC_VER
#include "boost/polygon/voronoi.hpp"
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
namespace Slic3r::Geometry {
class VoronoiDiagram
{
public:
using coord_type = double;
using voronoi_diagram_type = boost::polygon::voronoi_diagram<coord_type>;
using point_type = boost::polygon::point_data<voronoi_diagram_type::coordinate_type>;
using segment_type = boost::polygon::segment_data<voronoi_diagram_type::coordinate_type>;
using rect_type = boost::polygon::rectangle_data<voronoi_diagram_type::coordinate_type>;
using coordinate_type = voronoi_diagram_type::coordinate_type;
using vertex_type = voronoi_diagram_type::vertex_type;
using edge_type = voronoi_diagram_type::edge_type;
using cell_type = voronoi_diagram_type::cell_type;
using const_vertex_iterator = voronoi_diagram_type::const_vertex_iterator;
using const_edge_iterator = voronoi_diagram_type::const_edge_iterator;
using const_cell_iterator = voronoi_diagram_type::const_cell_iterator;
using vertex_container_type = voronoi_diagram_type::vertex_container_type;
using edge_container_type = voronoi_diagram_type::edge_container_type;
using cell_container_type = voronoi_diagram_type::cell_container_type;
enum class IssueType {
NO_ISSUE_DETECTED,
FINITE_EDGE_WITH_NON_FINITE_VERTEX,
MISSING_VORONOI_VERTEX,
NON_PLANAR_VORONOI_DIAGRAM,
VORONOI_EDGE_INTERSECTING_INPUT_SEGMENT,
UNKNOWN // Repairs are disabled in the constructor.
};
enum class State {
REPAIR_NOT_NEEDED, // The original Voronoi diagram doesn't have any issue.
REPAIR_SUCCESSFUL, // The original Voronoi diagram has some issues, but it was repaired.
REPAIR_UNSUCCESSFUL, // The original Voronoi diagram has some issues, but it wasn't repaired.
UNKNOWN // Repairs are disabled in the constructor.
};
VoronoiDiagram() = default;
virtual ~VoronoiDiagram() = default;
IssueType get_issue_type() const { return m_issue_type; }
State get_state() const { return m_state; }
bool is_valid() const { return m_state != State::REPAIR_UNSUCCESSFUL; }
void clear();
const vertex_container_type &vertices() const { return m_is_modified ? m_vertices : m_voronoi_diagram.vertices(); }
const edge_container_type &edges() const { return m_is_modified ? m_edges : m_voronoi_diagram.edges(); }
const cell_container_type &cells() const { return m_is_modified ? m_cells : m_voronoi_diagram.cells(); }
std::size_t num_vertices() const { return m_is_modified ? m_vertices.size() : m_voronoi_diagram.num_vertices(); }
std::size_t num_edges() const { return m_is_modified ? m_edges.size() : m_voronoi_diagram.num_edges(); }
std::size_t num_cells() const { return m_is_modified ? m_cells.size() : m_voronoi_diagram.num_cells(); }
template<typename SegmentIterator>
typename boost::polygon::enable_if<
typename boost::polygon::gtl_if<typename boost::polygon::is_segment_concept<
typename boost::polygon::geometry_concept<typename std::iterator_traits<SegmentIterator>::value_type>::type>::type>::type,
void>::type
construct_voronoi(SegmentIterator segment_begin, SegmentIterator segment_end, bool try_to_repair_if_needed = true);
template<typename PointIterator>
typename boost::polygon::enable_if<
typename boost::polygon::gtl_if<typename boost::polygon::is_point_concept<
typename boost::polygon::geometry_concept<typename std::iterator_traits<PointIterator>::value_type>::type>::type>::type,
void>::type
construct_voronoi(const PointIterator first, const PointIterator last)
{
boost::polygon::construct_voronoi(first, last, &m_voronoi_diagram);
m_state = State::UNKNOWN;
m_issue_type = IssueType::UNKNOWN;
}
template<typename PointIterator, typename SegmentIterator>
typename boost::polygon::enable_if<
typename boost::polygon::gtl_and<
typename boost::polygon::gtl_if<typename boost::polygon::is_point_concept<
typename boost::polygon::geometry_concept<typename std::iterator_traits<PointIterator>::value_type>::type>::type>::type,
typename boost::polygon::gtl_if<typename boost::polygon::is_segment_concept<typename boost::polygon::geometry_concept<
typename std::iterator_traits<SegmentIterator>::value_type>::type>::type>::type>::type,
void>::type
construct_voronoi(const PointIterator p_first, const PointIterator p_last, const SegmentIterator s_first, const SegmentIterator s_last)
{
boost::polygon::construct_voronoi(p_first, p_last, s_first, s_last, &m_voronoi_diagram);
m_state = State::UNKNOWN;
m_issue_type = IssueType::UNKNOWN;
}
// Try to detect cases when some Voronoi vertex is missing, when the Voronoi diagram
// is not planar or some Voronoi edge is intersecting input segment.
template<typename SegmentIterator>
static typename boost::polygon::enable_if<
typename boost::polygon::gtl_if<typename boost::polygon::is_segment_concept<
typename boost::polygon::geometry_concept<typename std::iterator_traits<SegmentIterator>::value_type>::type>::type>::type,
IssueType>::type
detect_known_issues(const VoronoiDiagram &voronoi_diagram, SegmentIterator segment_begin, SegmentIterator segment_end);
template<typename SegmentIterator>
typename boost::polygon::enable_if<
typename boost::polygon::gtl_if<typename boost::polygon::is_segment_concept<
typename boost::polygon::geometry_concept<typename std::iterator_traits<SegmentIterator>::value_type>::type>::type>::type,
VoronoiDiagram::IssueType>::type
try_to_repair_degenerated_voronoi_diagram_by_rotation(SegmentIterator segment_begin, SegmentIterator segment_end, double fix_angle);
template<typename SegmentIterator>
typename boost::polygon::enable_if<
typename boost::polygon::gtl_if<typename boost::polygon::is_segment_concept<
typename boost::polygon::geometry_concept<typename std::iterator_traits<SegmentIterator>::value_type>::type>::type>::type,
VoronoiDiagram::IssueType>::type
try_to_repair_degenerated_voronoi_diagram(SegmentIterator segment_begin, SegmentIterator segment_end);
private:
struct Segment
{
Point from;
Point to;
Segment() = delete;
explicit Segment(const Point &from, const Point &to) : from(from), to(to) {}
};
void copy_to_local(voronoi_diagram_type &voronoi_diagram);
// Detect issues related to Voronoi cells, or that can be detected by iterating over Voronoi cells.
// The first type of issue that can be detected is a missing Voronoi vertex, especially when it is
// missing at one of the endpoints of the input segment.
// The second type of issue that can be detected is a Voronoi edge that intersects the input segment.
template<typename SegmentIterator>
static typename boost::polygon::enable_if<
typename boost::polygon::gtl_if<typename boost::polygon::is_segment_concept<
typename boost::polygon::geometry_concept<typename std::iterator_traits<SegmentIterator>::value_type>::type>::type>::type,
IssueType>::type
detect_known_voronoi_cell_issues(const VoronoiDiagram &voronoi_diagram, SegmentIterator segment_begin, SegmentIterator segment_end);
static bool has_finite_edge_with_non_finite_vertex(const VoronoiDiagram &voronoi_diagram);
voronoi_diagram_type m_voronoi_diagram;
vertex_container_type m_vertices;
edge_container_type m_edges;
cell_container_type m_cells;
bool m_is_modified = false;
State m_state = State::UNKNOWN;
IssueType m_issue_type = IssueType::UNKNOWN;
public:
using SegmentIt = std::vector<Slic3r::Geometry::VoronoiDiagram::Segment>::iterator;
friend struct boost::polygon::segment_traits<Slic3r::Geometry::VoronoiDiagram::Segment>;
};
} // namespace Slic3r::Geometry
namespace boost::polygon {
template<> struct geometry_concept<Slic3r::Geometry::VoronoiDiagram::Segment>
{
typedef segment_concept type;
};
template<> struct segment_traits<Slic3r::Geometry::VoronoiDiagram::Segment>
{
using coordinate_type = coord_t;
using point_type = Slic3r::Point;
using segment_type = Slic3r::Geometry::VoronoiDiagram::Segment;
static inline point_type get(const segment_type &segment, direction_1d dir) { return dir.to_int() ? segment.to : segment.from; }
};
} // namespace boost::polygon
#endif // slic3r_Geometry_Voronoi_hpp_