// 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 { 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 KSP_2::Support_line Support_line; typedef KSP_2::Segment Segment; typedef KSP_2::Vertex Vertex; typedef KSP_2::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& support_line (std::size_t idx) const { return m_support_lines[idx]; } Support_line& 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() == KSP::no_element() ? "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& support_line_of_segment (const Segment& segment) const { return m_support_lines[segment.support_line_idx()]; } inline Support_line& support_line_of_segment (const Segment& segment) { return m_support_lines[segment.support_line_idx()]; } inline const Support_line& support_line_of_segment (std::size_t segment_idx) const { return support_line_of_segment(m_segments[segment_idx]); } inline Support_line& 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& support_line_of_vertex (const Vertex& vertex) const { return support_line_of_segment(vertex.segment_idx()); } inline Support_line& support_line_of_vertex (const Vertex& vertex) { return support_line_of_segment(vertex.segment_idx()); } inline const Support_line& support_line_of_vertex (std::size_t vertex_idx) const { return support_line_of_vertex(m_vertices[vertex_idx]); } inline Support_line& 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() != KSP::no_element(); } 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& 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& 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& 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 = KSP::no_element(); 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 != KSP::no_element()); 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(segment)); return std::size_t(m_support_lines.size() - 1); } Segment& add_segment (const Segment_2 segment, std::size_t input_idx = KSP::no_element()) { // Check if support line exists first Support_line new_support_line (segment); std::size_t support_line_idx = KSP::no_element(); 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 == KSP::no_element()) { support_line_idx = number_of_support_lines(); m_support_lines.push_back (new_support_line); if (input_idx == KSP::no_element()) { 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::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 = KSP::no_element()) { // 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 != KSP::no_element()) { 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 == KSP::no_element()) { 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& 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)); }); std::size_t nb_segments_before = m_segments.size(); std::size_t nb_vertices_before = m_vertices.size(); // 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() = KSP::no_element(); return target_idx; } void update_positions (FT time) { m_current_time = time; } }; }} // namespace CGAL::KSP_2 #endif // CGAL_KSP_2_DATA_STRUCTURE_H