// Copyright (c) 2019 GeometryFactory Sarl (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // // $URL$ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // // Author(s) : Simon Giraudot #ifndef CGAL_KSP_2_DATA_STRUCTURE_H #define CGAL_KSP_2_DATA_STRUCTURE_H #include #include #include #include #include #include namespace CGAL { namespace KSP_2 { namespace internal { template class Data_structure { public: typedef GeomTraits Kernel; typedef typename Kernel::FT FT; typedef typename Kernel::Point_2 Point_2; typedef typename Kernel::Vector_2 Vector_2; typedef typename Kernel::Ray_2 Ray_2; typedef typename Kernel::Line_2 Line_2; typedef typename Kernel::Segment_2 Segment_2; typedef Support_line_2 Support_line_DS; typedef CGAL::KSP_2::internal::Vertex Vertex; typedef CGAL::KSP_2::internal::Segment Segment; typedef CGAL::KSP_2::internal::Meta_vertex Meta_vertex; typedef std::vector Support_lines; typedef std::vector Segments; typedef std::vector Vertices; typedef std::vector Meta_vertices; private: // Main data structure Support_lines m_support_lines; Segments m_segments; Vertices m_vertices; Meta_vertices m_meta_vertices; // Helping data structures std::map m_meta_map; FT m_current_time; public: Data_structure() : m_current_time(0) { } void print() const { for (std::size_t i = 0; i < m_support_lines.size(); ++i) { std::cerr << "* Support_line[" << i << "]" << std::endl; for (std::size_t segment_idx : m_support_lines[i].segments_idx()) { std::cerr << "** Segment[" << segment_idx << "]" << std::endl; std::cerr << "*** Vertex[" << segment(segment_idx).source_idx() << "]" << std::endl; std::cerr << "*** Vertex[" << segment(segment_idx).target_idx() << "]" << std::endl; } } } const FT& current_time() const { return m_current_time; } std::size_t number_of_vertices() const { return m_vertices.size(); } const Vertex& vertex(std::size_t idx) const { return m_vertices[idx]; } Vertex& vertex(std::size_t idx) { return m_vertices[idx]; } std::size_t number_of_segments() const { return m_segments.size(); } const Segment& segment(std::size_t idx) const { return m_segments[idx]; } Segment& segment(std::size_t idx) { return m_segments[idx]; } std::size_t number_of_support_lines() const { return m_support_lines.size(); } const Support_line_DS& support_line(std::size_t idx) const { return m_support_lines[idx]; } Support_line_DS& support_line(std::size_t idx) { return m_support_lines[idx]; } std::size_t number_of_meta_vertices() const { return m_meta_vertices.size(); } const Meta_vertex& meta_vertex(std::size_t idx) const { return m_meta_vertices[idx]; } Meta_vertex& meta_vertex(std::size_t idx) { return m_meta_vertices[idx]; } std::string segment_str(std::size_t segment_idx) const { return "Segment[" + std::to_string(segment_idx) + " from " + (segment(segment_idx).input_idx() == std::size_t(-1) ? "bbox" : std::to_string(segment(segment_idx).input_idx())) + "](v" + std::to_string(segment(segment_idx).source_idx()) + "->v" + std::to_string(segment(segment_idx).target_idx()) + ")"; } std::string vertex_str(std::size_t vertex_idx) const { return "Vertex[" + std::to_string(vertex_idx) + "]"; } // Vertex/idx -> Point_2 inline Point_2 point_of_vertex(const Vertex& vertex, FT time) const { return support_line_of_vertex(vertex).to_2d(vertex.point(time)); } inline Point_2 point_of_vertex(std::size_t vertex_idx, FT time) const { return point_of_vertex(m_vertices[vertex_idx], time); } inline Point_2 point_of_vertex(const Vertex& vertex) const { return point_of_vertex(vertex, m_current_time); } inline Point_2 point_of_vertex(std::size_t vertex_idx) const { return point_of_vertex(vertex_idx, m_current_time); } // Vertex/idx -> Vector_2 inline Vector_2 direction_of_vertex(const Vertex& vertex) const { return Vector_2(support_line_of_vertex(vertex).to_2d(vertex.point(m_current_time)), support_line_of_vertex(vertex).to_2d(vertex.point(m_current_time) + vertex.direction())); } inline Vector_2 direction_of_vertex(std::size_t vertex_idx) const { return direction_of_vertex(m_vertices[vertex_idx]); } // Vertex/idx -> Segment inline const Segment& segment_of_vertex(const Vertex& vertex) const { return m_segments[vertex.segment_idx()]; } inline Segment& segment_of_vertex(const Vertex& vertex) { return m_segments[vertex.segment_idx()]; } inline const Segment& segment_of_vertex(std::size_t vertex_idx) const { return segment_of_vertex(m_vertices[vertex_idx]); } inline Segment& segment_of_vertex(std::size_t vertex_idx) { return segment_of_vertex(m_vertices[vertex_idx]); } // Segment/idx -> source Vertex inline const Vertex& source_of_segment(const Segment& segment) const { return m_vertices[segment.source_idx()]; } inline Vertex& source_of_segment(const Segment& segment) { return m_vertices[segment.source_idx()]; } inline const Vertex& source_of_segment(std::size_t segment_idx) const { return source_of_segment(m_segments[segment_idx]); } inline Vertex& source_of_segment(std::size_t segment_idx) { return source_of_segment(m_segments[segment_idx]); } // Segment/idx -> target Vertex inline const Vertex& target_of_segment(const Segment& segment) const { return m_vertices[segment.target_idx()]; } inline Vertex& target_of_segment(const Segment& segment) { return m_vertices[segment.target_idx()]; } inline const Vertex& target_of_segment(std::size_t segment_idx) const { return target_of_segment(m_segments[segment_idx]); } inline Vertex& target_of_segment(std::size_t segment_idx) { return target_of_segment(m_segments[segment_idx]); } // idx -> opposite Vertex inline const Vertex& opposite_vertex(std::size_t vertex_idx) const { const Segment& segment = segment_of_vertex(vertex_idx); CGAL_assertion(segment.source_idx() == vertex_idx || segment.target_idx() == vertex_idx); return (segment.source_idx() == vertex_idx ? m_vertices[segment.target_idx()] : m_vertices[segment.source_idx()]); } // Segment/idx -> Support_line inline const Support_line_DS& support_line_of_segment(const Segment& segment) const { return m_support_lines[segment.support_line_idx()]; } inline Support_line_DS& support_line_of_segment(const Segment& segment) { return m_support_lines[segment.support_line_idx()]; } inline const Support_line_DS& support_line_of_segment(std::size_t segment_idx) const { return support_line_of_segment(m_segments[segment_idx]); } inline Support_line_DS& support_line_of_segment(std::size_t segment_idx) { return support_line_of_segment(m_segments[segment_idx]); } // Vertex/idx -> Support_line inline const Support_line_DS& support_line_of_vertex(const Vertex& vertex) const { return support_line_of_segment(vertex.segment_idx()); } inline Support_line_DS& support_line_of_vertex(const Vertex& vertex) { return support_line_of_segment(vertex.segment_idx()); } inline const Support_line_DS& support_line_of_vertex(std::size_t vertex_idx) const { return support_line_of_vertex(m_vertices[vertex_idx]); } inline Support_line_DS& support_line_of_vertex(std::size_t vertex_idx) { return support_line_of_vertex(m_vertices[vertex_idx]); } // Vertex/idx -> Meta_vertex inline const Meta_vertex& meta_vertex_of_vertex(const Vertex& vertex) const { return m_meta_vertices[vertex.meta_vertex_idx()]; } inline Meta_vertex& meta_vertex_of_vertex(const Vertex& vertex) { return m_meta_vertices[vertex.meta_vertex_idx()]; } inline const Meta_vertex& meta_vertex_of_vertex(std::size_t vertex_idx) const { return meta_vertex_of_vertex(m_vertices[vertex_idx]); } inline Meta_vertex& meta_vertex_of_vertex(std::size_t vertex_idx) { return meta_vertex_of_vertex(m_vertices[vertex_idx]); } bool has_meta_vertex(const Vertex& vertex) const { return vertex.meta_vertex_idx() != std::size_t(-1); } bool has_meta_vertex(std::size_t vertex_idx) const { return has_meta_vertex(m_vertices[vertex_idx]); } FT position_of_meta_vertex_on_support_line(std::size_t meta_vertex_idx, std::size_t support_line_idx) const { return support_line(support_line_idx).to_1d(meta_vertex(meta_vertex_idx).point()); } inline bool meta_vertex_exists(const Point_2& point) const { return m_meta_map.find(point) != m_meta_map.end(); } void get_vertices_of_meta_vertex(std::size_t meta_vertex_idx, std::vector& vertices_idx) const { const Meta_vertex& meta_vertex = m_meta_vertices[meta_vertex_idx]; for (std::size_t support_line_idx : meta_vertex.support_lines_idx()) { const Support_line_DS& support_line = m_support_lines[support_line_idx]; for (std::size_t segment_idx : support_line.segments_idx()) { const Segment& segment = m_segments[segment_idx]; for (std::size_t vertex_idx : { segment.source_idx(), segment.target_idx() }) if (m_vertices[vertex_idx].meta_vertex_idx() == meta_vertex_idx) vertices_idx.push_back(vertex_idx); } } } inline CGAL::Bbox_2 bbox(const Vertex& vertex) const { return point_of_vertex(vertex).bbox(); } inline CGAL::Bbox_2 bbox(const Support_line_DS& support_line) const { return std::accumulate(support_line.segments_idx().begin(), support_line.segments_idx().end(), CGAL::Bbox_2(), [&](const CGAL::Bbox_2& bbox_2, const std::size_t& segment_idx) -> CGAL::Bbox_2 { return bbox_2 + bbox(source_of_segment(segment_idx)) + bbox(target_of_segment(segment_idx)); }); } bool is_segment_frozen(std::size_t segment_idx) const { return (source_of_segment(segment_idx).is_frozen() && target_of_segment(segment_idx).is_frozen()); } // idx -> Segment_2 Segment_2 segment_2(std::size_t segment_idx) const { const Segment& segment = m_segments[segment_idx]; const Support_line_DS& support_line = m_support_lines[segment.support_line_idx()]; const Vertex& source = m_vertices[segment.source_idx()]; const Vertex& target = m_vertices[segment.target_idx()]; return Segment_2(support_line.to_2d(source.point(m_current_time)), support_line.to_2d(target.point(m_current_time))); } bool is_bbox_support_line(std::size_t support_line_idx) const { return support_line_idx < 4; } bool is_bbox_segment(std::size_t segment_idx) const { return is_bbox_support_line(segment(segment_idx).support_line_idx()); } bool is_bbox_meta_vertex(std::size_t meta_vertex_idx) const { for (std::size_t support_line_idx : meta_vertex(meta_vertex_idx).support_lines_idx()) if (is_bbox_support_line(support_line_idx)) return true; return false; } bool is_bbox_meta_edge(std::size_t source_idx, std::size_t target_idx) const { std::size_t common_line_idx = std::size_t(-1); for (std::size_t support_line_idx : meta_vertex(source_idx).support_lines_idx()) if (m_meta_vertices[target_idx].support_lines_idx().find(support_line_idx) != m_meta_vertices[target_idx].support_lines_idx().end()) { common_line_idx = support_line_idx; break; } CGAL_assertion(common_line_idx != std::size_t(-1)); return is_bbox_support_line(common_line_idx); } bool is_meta_vertex_active(std::size_t meta_vertex_idx) const { for (std::size_t support_line_idx : meta_vertex(meta_vertex_idx).support_lines_idx()) for (std::size_t segment_idx : support_line(support_line_idx).segments_idx()) for (std::size_t vertex_idx : { segment(segment_idx).source_idx(), segment(segment_idx).target_idx() }) if (vertex(vertex_idx).meta_vertex_idx() == meta_vertex_idx) return true; return false; } bool is_meta_vertex_intersection(std::size_t meta_vertex_idx) const { bool found_one = false; for (std::size_t support_line_idx : meta_vertex(meta_vertex_idx).support_lines_idx()) { bool broken = false; for (std::size_t segment_idx : support_line(support_line_idx).segments_idx()) { for (std::size_t vertex_idx : { segment(segment_idx).source_idx(), segment(segment_idx).target_idx() }) { if (vertex(vertex_idx).meta_vertex_idx() == meta_vertex_idx) { if (found_one) return true; found_one = true; broken = true; break; } } if (broken) break; } } return false; } bool is_meta_vertex_deadend_of_vertex(std::size_t meta_vertex_idx, std::size_t vertex_idx) const { return meta_vertex(meta_vertex_idx).is_deadend_of(segment_of_vertex(vertex_idx).support_line_idx()); } void make_meta_vertex_deadend_of_vertex(std::size_t meta_vertex_idx, std::size_t vertex_idx) { meta_vertex(meta_vertex_idx).make_deadend_of(segment_of_vertex(vertex_idx).support_line_idx()); } void make_meta_vertex_no_longer_deadend_of_vertex(std::size_t meta_vertex_idx, std::size_t vertex_idx) { meta_vertex(meta_vertex_idx).make_no_longer_deadend_of(segment_of_vertex(vertex_idx).support_line_idx()); } std::size_t add_support_line(const Segment_2& segment) { m_support_lines.push_back(Support_line_DS(segment)); return std::size_t(m_support_lines.size() - 1); } Segment& add_segment(const Segment_2 segment, std::size_t input_idx = std::size_t(-1)) { // Check if support line exists first Support_line_DS new_support_line(segment); std::size_t support_line_idx = std::size_t(-1); for (std::size_t i = 0; i < number_of_support_lines(); ++i) if (new_support_line == support_line(i)) { support_line_idx = i; break; } if (support_line_idx == std::size_t(-1)) { support_line_idx = number_of_support_lines(); m_support_lines.push_back(new_support_line); if (input_idx == std::size_t(-1)) { m_support_lines.back().minimum() = m_support_lines.back().to_1d(segment.source()); m_support_lines.back().maximum() = m_support_lines.back().to_1d(segment.target()); } else { FT max_negative = -(std::numeric_limits::max)(); FT min_positive = (std::numeric_limits::max)(); for (std::size_t i = 0; i < 4; ++i) { Point_2 point; if (!KSP::internal::intersection(m_support_lines[i].line(), m_support_lines.back().line(), point)) continue; FT position = m_support_lines.back().to_1d(point); if (position < 0 && position > max_negative) max_negative = position; if (position > 0 && position < min_positive) min_positive = position; } CGAL_assertion(max_negative != -(std::numeric_limits::max)() && min_positive != -(std::numeric_limits::min)()); m_support_lines.back().minimum() = max_negative; m_support_lines.back().maximum() = min_positive; } } else support_line(support_line_idx).connected_components()++; std::size_t segment_idx = m_segments.size(); m_segments.push_back(Segment(input_idx, support_line_idx)); m_support_lines[support_line_idx].segments_idx().push_back(segment_idx); std::size_t source_idx = m_vertices.size(); m_vertices.push_back(Vertex(m_support_lines[support_line_idx].to_1d(segment.source()), segment_idx)); std::size_t target_idx = m_vertices.size(); m_vertices.push_back(Vertex(m_support_lines[support_line_idx].to_1d(segment.target()), segment_idx)); // Keep segment ordered if (m_vertices[source_idx].point(0) > m_vertices[target_idx].point(0)) std::swap(source_idx, target_idx); m_segments[segment_idx].source_idx() = source_idx; m_segments[segment_idx].target_idx() = target_idx; return m_segments.back(); } std::size_t add_meta_vertex(const Point_2& point, std::size_t support_line_idx_0, std::size_t support_line_idx_1 = std::size_t(-1)) { // Avoid several points almost equal Point_2 p(1e-10 * std::floor(CGAL::to_double(point.x()) / 1e-10), 1e-10 * std::floor(CGAL::to_double(point.y()) / 1e-10)); typename std::map::iterator iter; bool inserted = false; std::tie(iter, inserted) = m_meta_map.insert(std::make_pair(p, number_of_meta_vertices())); if (inserted) m_meta_vertices.push_back(Meta_vertex(p)); std::size_t meta_vertex_idx = iter->second; for (std::size_t support_line_idx : { support_line_idx_0, support_line_idx_1 }) { if (support_line_idx != std::size_t(-1)) { meta_vertex(meta_vertex_idx).support_lines_idx().insert(support_line_idx); if (std::find(support_line(support_line_idx).meta_vertices_idx().begin(), support_line(support_line_idx).meta_vertices_idx().end(), meta_vertex_idx) == support_line(support_line_idx).meta_vertices_idx().end()) support_line(support_line_idx).meta_vertices_idx().push_back(meta_vertex_idx); } } // Special case = meta vertex is deadend of one line if (support_line_idx_1 == std::size_t(-1)) { meta_vertex(meta_vertex_idx).make_deadend_of(support_line_idx_0); } return meta_vertex_idx; } void attach_vertex_to_meta_vertex(std::size_t vertex_idx, std::size_t meta_vertex_idx) { CGAL_assertion(!has_meta_vertex(vertex_idx)); CGAL_assertion_msg(meta_vertex(meta_vertex_idx).support_lines_idx().find (segment_of_vertex(vertex_idx).support_line_idx()) != meta_vertex(meta_vertex_idx).support_lines_idx().end(), "Trying to attach a vertex to a meta vertex not on its support line"); vertex(vertex_idx).meta_vertex_idx() = meta_vertex_idx; } void cut_segment(std::size_t segment_idx, std::size_t meta_vertex_idx) { std::vector vec(1, meta_vertex_idx); cut_segment(segment_idx, vec); } void cut_segment(std::size_t segment_idx, std::vector& meta_vertices_idx) { Segment& segment = m_segments[segment_idx]; std::size_t input_idx = segment.input_idx(); std::size_t support_line_idx = segment.support_line_idx(); // std::size_t source_idx = segment.source_idx(); std::size_t target_idx = segment.target_idx(); Support_line_DS& support_line = support_line_of_segment(segment_idx); std::sort(meta_vertices_idx.begin(), meta_vertices_idx.end(), [&](const std::size_t& a, const std::size_t& b) -> bool { return (position_of_meta_vertex_on_support_line(a, support_line_idx) < position_of_meta_vertex_on_support_line(b, support_line_idx)); }); // Attach to existing endpoint std::size_t new_target_idx = m_vertices.size(); m_vertices.push_back(Vertex(position_of_meta_vertex_on_support_line(meta_vertices_idx.front(), support_line_idx))); m_vertices[new_target_idx].segment_idx() = segment_idx; segment.target_idx() = new_target_idx; attach_vertex_to_meta_vertex(new_target_idx, meta_vertices_idx.front()); // Create new segments for (std::size_t i = 0; i < meta_vertices_idx.size() - 1; ++i) { std::size_t sidx = m_segments.size(); m_segments.push_back(Segment(input_idx, support_line_idx)); support_line.segments_idx().push_back(sidx); std::size_t source_idx = m_vertices.size(); m_vertices.push_back(Vertex(position_of_meta_vertex_on_support_line(meta_vertices_idx[i], support_line_idx))); m_vertices[source_idx].segment_idx() = sidx; m_segments[sidx].source_idx() = source_idx; attach_vertex_to_meta_vertex(source_idx, meta_vertices_idx[i]); std::size_t target_idx = m_vertices.size(); m_vertices.push_back(Vertex(position_of_meta_vertex_on_support_line(meta_vertices_idx[i + 1], support_line_idx))); m_vertices[target_idx].segment_idx() = sidx; m_segments[sidx].target_idx() = target_idx; attach_vertex_to_meta_vertex(source_idx, meta_vertices_idx[i + 1]); } // Create final segment and attach to existing endpoint std::size_t sidx = m_segments.size(); m_segments.push_back(Segment(input_idx, support_line_idx)); support_line.segments_idx().push_back(sidx); std::size_t new_source_idx = m_vertices.size(); m_vertices.push_back(Vertex(position_of_meta_vertex_on_support_line(meta_vertices_idx.back(), support_line_idx))); m_vertices[new_source_idx].segment_idx() = sidx; m_segments[sidx].source_idx() = new_source_idx; attach_vertex_to_meta_vertex(new_source_idx, meta_vertices_idx.back()); m_vertices[target_idx].segment_idx() = sidx; m_segments[sidx].target_idx() = target_idx; } std::size_t propagate_segment(std::size_t vertex_idx) { // Create a new segment std::size_t segment_idx = m_segments.size(); m_segments.push_back(Segment(segment_of_vertex(vertex_idx).input_idx(), segment_of_vertex(vertex_idx).support_line_idx())); support_line_of_vertex(vertex_idx).segments_idx().push_back(segment_idx); // Create new vertices std::size_t source_idx = m_vertices.size(); m_vertices.push_back(Vertex(m_vertices[vertex_idx])); std::size_t target_idx = m_vertices.size(); m_vertices.push_back(Vertex(m_vertices[vertex_idx])); // Connect segments and vertices m_segments[segment_idx].source_idx() = source_idx; m_segments[segment_idx].target_idx() = target_idx; m_vertices[source_idx].segment_idx() = segment_idx; m_vertices[target_idx].segment_idx() = segment_idx; CGAL_assertion(m_vertices[vertex_idx].direction() != 0); // Keep vertices ordered on the segment if (m_vertices[vertex_idx].direction() < 0) std::swap(source_idx, target_idx); // Freeze one end m_vertices[source_idx].freeze(m_current_time); // Release other end m_vertices[target_idx].meta_vertex_idx() = std::size_t(-1); return target_idx; } void update_positions(FT time) { m_current_time = time; } }; } // namespace internal } // namespace KSP_2 } // namespace CGAL #endif // CGAL_KSP_2_DATA_STRUCTURE_H