mirror of https://github.com/CGAL/cgal
232 lines
6.5 KiB
C++
232 lines
6.5 KiB
C++
// Copyright (c) 2023 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) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot
|
|
|
|
#ifndef CGAL_KSP_3_FACEPROPAGATION_H
|
|
#define CGAL_KSP_3_FACEPROPAGATION_H
|
|
|
|
#include <CGAL/license/Kinetic_space_partition.h>
|
|
|
|
// Internal includes.
|
|
#include <CGAL/KSP/utils.h>
|
|
#include <CGAL/KSP/debug.h>
|
|
#include <CGAL/KSP/parameters.h>
|
|
|
|
#include <CGAL/KSP_3/Data_structure.h>
|
|
|
|
namespace CGAL {
|
|
namespace KSP_3 {
|
|
namespace internal {
|
|
|
|
#ifdef DOXYGEN_RUNNING
|
|
#else
|
|
|
|
template<typename GeomTraits, typename IntersectionKernel>
|
|
class FacePropagation {
|
|
|
|
public:
|
|
using Kernel = GeomTraits;
|
|
using Intersection_kernel = IntersectionKernel;
|
|
|
|
private:
|
|
using FT = typename Kernel::FT;
|
|
using Point_2 = typename Kernel::Point_2;
|
|
using Vector_2 = typename Kernel::Vector_2;
|
|
using Segment_2 = typename Kernel::Segment_2;
|
|
using Direction_2 = typename Kernel::Direction_2;
|
|
using Line_2 = typename Kernel::Line_2;
|
|
|
|
using Data_structure = CGAL::KSP_3::internal::Data_structure<Kernel, Intersection_kernel>;
|
|
|
|
using IVertex = typename Data_structure::IVertex;
|
|
using IEdge = typename Data_structure::IEdge;
|
|
using IFace = typename Data_structure::IFace;
|
|
|
|
using PVertex = typename Data_structure::PVertex;
|
|
using PEdge = typename Data_structure::PEdge;
|
|
using PFace = typename Data_structure::PFace;
|
|
|
|
using Bbox_2 = CGAL::Bbox_2;
|
|
using Face_index = typename Data_structure::Face_index;
|
|
|
|
using Parameters = KSP::internal::Parameters_3<FT>;
|
|
|
|
using Face_event = typename Data_structure::Support_plane::Face_event;
|
|
|
|
using From_exact = CGAL::Cartesian_converter<Intersection_kernel, Kernel>;
|
|
|
|
struct Face_event_order {
|
|
bool operator()(const Face_event& a, const Face_event& b) {
|
|
return a.time > b.time;
|
|
}
|
|
};
|
|
|
|
public:
|
|
FacePropagation(Data_structure& data, const Parameters& parameters) :
|
|
m_data(data), m_parameters(parameters),
|
|
m_min_time(-FT(1)), m_max_time(-FT(1))
|
|
{ }
|
|
|
|
std::size_t propagate(std::size_t k) {
|
|
std::size_t num_events = 0;
|
|
m_data.reset_to_initialization();
|
|
|
|
for (std::size_t i = 0; i < m_data.number_of_support_planes(); ++i)
|
|
m_data.k(i) = static_cast<int>(k);
|
|
|
|
initialize_queue();
|
|
|
|
while (!m_face_queue.empty())
|
|
run(num_events);
|
|
|
|
return num_events;
|
|
}
|
|
|
|
void clear() {
|
|
m_face_queue.clear();
|
|
m_min_time = -FT(1);
|
|
m_max_time = -FT(1);
|
|
}
|
|
|
|
private:
|
|
Data_structure& m_data;
|
|
const Parameters& m_parameters;
|
|
|
|
FT m_min_time;
|
|
FT m_max_time;
|
|
|
|
std::priority_queue<typename Data_structure::Support_plane::Face_event, std::vector<Face_event>, Face_event_order> m_face_queue;
|
|
|
|
/*******************************
|
|
** IDENTIFY EVENTS **
|
|
********************************/
|
|
|
|
void initialize_queue() {
|
|
m_data.fill_event_queue(m_face_queue);
|
|
}
|
|
|
|
/*******************************
|
|
** RUNNING **
|
|
********************************/
|
|
|
|
std::size_t run(
|
|
const std::size_t initial_iteration) {
|
|
|
|
std::size_t iteration = initial_iteration;
|
|
while (!m_face_queue.empty()) {
|
|
// m_queue.print();
|
|
|
|
const Face_event event = m_face_queue.top();
|
|
m_face_queue.pop();
|
|
|
|
++iteration;
|
|
|
|
apply(event);
|
|
}
|
|
return iteration;
|
|
}
|
|
|
|
/*******************************
|
|
** HANDLE EVENTS **
|
|
********************************/
|
|
|
|
void apply(const Face_event& event) {
|
|
if (m_data.igraph().face(event.face).part_of_partition) {
|
|
return;
|
|
}
|
|
|
|
std::size_t line = m_data.line_idx(event.crossed_edge);
|
|
auto& sp = m_data.support_plane(event.support_plane);
|
|
int& k = sp.k();
|
|
|
|
const typename Data_structure::Intersection_graph::Face_property& face = m_data.igraph().face(event.face);
|
|
|
|
From_exact from_exact;
|
|
Point_2 on_edge = sp.to_2d(from_exact(m_data.point_3(m_data.source(event.crossed_edge))));
|
|
Point_2 center = from_exact(CGAL::centroid(face.pts.begin(), face.pts.end()));
|
|
Point_2 origin = sp.centroid();
|
|
Vector_2 dir = sp.to_2d(from_exact(m_data.igraph().line(line).to_vector()));
|
|
dir = Vector_2(-dir.y(), dir.x()); // Vector orthogonal to line.
|
|
|
|
bool need_check = false;
|
|
|
|
// Only allow crossing edges away from the input polygon centroid.
|
|
if (((center - on_edge) * dir) * ((origin - on_edge) * dir) > 0)
|
|
need_check = true;
|
|
|
|
if (need_check || !sp.has_crossed_line(line)) {
|
|
// Check intersection against kinetic intervals from other support planes
|
|
int crossing = 0;
|
|
auto kis = m_data.igraph().kinetic_intervals(event.crossed_edge);
|
|
for (auto ki = kis.first; ki != kis.second; ki++) {
|
|
if (ki->first == event.support_plane)
|
|
continue;
|
|
|
|
for (std::size_t i = 0; i < ki->second.size(); i++) {
|
|
// Exactly on one
|
|
if (ki->second[i].first == event.intersection_bary) {
|
|
if (ki->second[i].second < event.time) {
|
|
crossing++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Within an interval
|
|
if (ki->second[i].first > event.intersection_bary && ki->second[i - 1].first < event.intersection_bary) {
|
|
FT interval_pos = (event.intersection_bary - ki->second[i - 1].first) / (ki->second[i].first - ki->second[i - 1].first);
|
|
FT interval_time = interval_pos * (ki->second[i].second - ki->second[i - 1].second) + ki->second[i - 1].second;
|
|
|
|
if (event.time > interval_time) {
|
|
crossing++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if the k value is sufficient for crossing the edge.
|
|
if (k <= crossing)
|
|
return;
|
|
|
|
// The edge can be crossed.
|
|
// Adjust k value
|
|
k -= crossing;
|
|
|
|
m_data.support_plane(event.support_plane).set_crossed_line(line);
|
|
}
|
|
|
|
// Associate IFace to mesh.
|
|
PFace f = m_data.add_iface_to_mesh(event.support_plane, event.face);
|
|
|
|
// Calculate events for new border edges.
|
|
// Iterate inside of this face, check if each opposite edge is border and on bbox and then calculate intersection times.
|
|
std::vector<IEdge> border;
|
|
m_data.support_plane(event.support_plane).get_border(m_data.igraph(), f.second, border);
|
|
|
|
for (IEdge edge : border) {
|
|
Face_event fe;
|
|
FT t = m_data.calculate_edge_intersection_time(event.support_plane, edge, fe);
|
|
if (t > 0)
|
|
m_face_queue.push(fe);
|
|
}
|
|
}
|
|
};
|
|
|
|
#endif //DOXYGEN_RUNNING
|
|
|
|
} // namespace internal
|
|
} // namespace KSP_3
|
|
} // namespace CGAL
|
|
|
|
#endif // CGAL_KSP_3_FACEPROPAGATION_H
|