cgal/Kinetic_space_partition/include/CGAL/KSP_2/Data_structure.h

670 lines
22 KiB
C++

// 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 <CGAL/license/Kinetic_space_partition.h>
#include <CGAL/KSP/utils.h>
#include <CGAL/KSP_2/Support_line.h>
#include <CGAL/KSP_2/Segment.h>
#include <CGAL/KSP_2/Vertex.h>
#include <CGAL/KSP_2/Meta_vertex.h>
namespace CGAL {
namespace KSP_2 {
namespace internal {
template <typename GeomTraits>
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<Kernel> Support_line_DS;
typedef CGAL::KSP_2::internal::Vertex<FT> Vertex;
typedef CGAL::KSP_2::internal::Segment Segment;
typedef CGAL::KSP_2::internal::Meta_vertex<Point_2> Meta_vertex;
typedef std::vector<Support_line_DS> Support_lines;
typedef std::vector<Segment> Segments;
typedef std::vector<Vertex> Vertices;
typedef std::vector<Meta_vertex> 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<Point_2, std::size_t> 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<std::size_t>& 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<FT>::max)();
FT min_positive = (std::numeric_limits<FT>::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<FT>::max)()
&& min_positive != -(std::numeric_limits<FT>::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<Point_2, std::size_t>::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<std::size_t> vec(1, meta_vertex_idx);
cut_segment(segment_idx, vec);
}
void cut_segment(std::size_t segment_idx, std::vector<std::size_t>& 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