7#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
8#include <CGAL/Delaunay_triangulation_2.h>
9#include <CGAL/Triangulation_vertex_base_with_info_2.h>
17typedef CGAL::Exact_predicates_inexact_constructions_kernel
K;
18typedef CGAL::Triangulation_vertex_base_with_info_2<size_t, K>
Vb;
19typedef CGAL::Triangulation_data_structure_2<Vb>
Tds;
20typedef CGAL::Delaunay_triangulation_2<K, Tds>
Delaunay;
24 std::vector<int> faces;
26 if (points.size() < 3) {
27 LOG_ERROR <<
"Need at least 3 points for triangulation";
35 std::vector<std::pair<Point_2, size_t>> cgal_points;
36 for (
size_t i = 0; i < points.size(); ++i) {
37 cgal_points.push_back(std::make_pair(
38 Point_2(points[i].x, points[i].y), i
42 dt.insert(cgal_points.begin(), cgal_points.end());
45 for (
auto fit = dt.finite_faces_begin(); fit != dt.finite_faces_end(); ++fit) {
47 size_t v0 = fit->vertex(0)->info();
48 size_t v1 = fit->vertex(1)->info();
49 size_t v2 = fit->vertex(2)->info();
58 LOG_INFO <<
"Delaunay triangulation: " << points.size() <<
" points -> "
59 << (faces.size() / 3) <<
" triangles";
65 const std::vector<int>& faces,
66 const std::vector<cv::Point2f>& vertices,
67 double max_edge_threshold) {
69 std::vector<int> filtered_faces;
71 if (faces.size() % 3 != 0) {
72 LOG_ERROR <<
"Faces array size must be multiple of 3";
73 return filtered_faces;
76 size_t n_triangles = faces.size() / 3;
78 for (
size_t i = 0; i < n_triangles; ++i) {
81 int v1 = faces[idx + 1];
82 int v2 = faces[idx + 2];
85 if (v0 < 0 || v1 < 0 || v2 < 0 ||
86 static_cast<size_t>(v0) >= vertices.size() ||
static_cast<size_t>(v1) >= vertices.size() ||
static_cast<size_t>(v2) >= vertices.size()) {
88 LOG_WARN <<
"Invalid vertex index in triangle " << i
89 <<
" (v0=" << v0 <<
" v1=" << v1 <<
" v2=" << v2
90 <<
", nVerts=" << vertices.size() <<
")";
96 cv::Point2f p0 = vertices[v0];
97 cv::Point2f p1 = vertices[v1];
98 cv::Point2f p2 = vertices[v2];
100 double e01 = std::sqrt((p1.x - p0.x) * (p1.x - p0.x) + (p1.y - p0.y) * (p1.y - p0.y));
101 double e12 = std::sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
102 double e20 = std::sqrt((p0.x - p2.x) * (p0.x - p2.x) + (p0.y - p2.y) * (p0.y - p2.y));
104 double max_edge = std::max({e01, e12, e20});
107 if (max_edge <= max_edge_threshold) {
108 filtered_faces.push_back(v0);
109 filtered_faces.push_back(v1);
110 filtered_faces.push_back(v2);
114 size_t removed = n_triangles - (filtered_faces.size() / 3);
116 LOG_INFO <<
"Filtered " << removed <<
" irregular triangles (edge > "
117 << max_edge_threshold <<
")";
120 return filtered_faces;
124 const std::vector<int>& faces,
125 const std::vector<cv::Point2f>& vertices) {
127 std::vector<double> edge_lengths;
129 if (faces.size() % 3 != 0) {
130 LOG_ERROR <<
"Faces array size must be multiple of 3";
134 size_t n_triangles = faces.size() / 3;
135 edge_lengths.reserve(n_triangles * 3);
137 for (
size_t i = 0; i < n_triangles; ++i) {
140 int v1 = faces[idx + 1];
141 int v2 = faces[idx + 2];
143 if (v0 >= vertices.size() || v1 >= vertices.size() || v2 >= vertices.size()) {
145 edge_lengths.push_back(std::nan(
""));
146 edge_lengths.push_back(std::nan(
""));
147 edge_lengths.push_back(std::nan(
""));
151 cv::Point2f p0 = vertices[v0];
152 cv::Point2f p1 = vertices[v1];
153 cv::Point2f p2 = vertices[v2];
155 double e01 = std::sqrt((p1.x - p0.x) * (p1.x - p0.x) + (p1.y - p0.y) * (p1.y - p0.y));
156 double e12 = std::sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
157 double e20 = std::sqrt((p0.x - p2.x) * (p0.x - p2.x) + (p0.y - p2.y) * (p0.y - p2.y));
159 edge_lengths.push_back(e01);
160 edge_lengths.push_back(e12);
161 edge_lengths.push_back(e20);
168 std::vector<int> flipped;
170 if (faces.size() % 3 != 0) {
171 LOG_ERROR <<
"Faces array size must be multiple of 3";
175 flipped.reserve(faces.size());
178 for (
size_t i = 0; i < faces.size(); i += 3) {
179 flipped.push_back(faces[i]);
180 flipped.push_back(faces[i + 2]);
181 flipped.push_back(faces[i + 1]);
188 const std::vector<int>& faces,
189 const std::vector<cv::Point2f>& vertices) {
191 std::vector<cv::Point2f> centroids;
193 if (faces.size() % 3 != 0) {
194 LOG_ERROR <<
"Faces array size must be multiple of 3";
198 size_t n_triangles = faces.size() / 3;
199 centroids.reserve(n_triangles);
201 for (
size_t i = 0; i < n_triangles; ++i) {
204 int v1 = faces[idx + 1];
205 int v2 = faces[idx + 2];
207 if (v0 >= vertices.size() || v1 >= vertices.size() || v2 >= vertices.size()) {
209 centroids.push_back(cv::Point2f(std::nan(
""), std::nan(
"")));
213 cv::Point2f p0 = vertices[v0];
214 cv::Point2f p1 = vertices[v1];
215 cv::Point2f p2 = vertices[v2];
217 float cx = (p0.x + p1.x + p2.x) / 3.0f;
218 float cy = (p0.y + p1.y + p2.y) / 3.0f;
220 centroids.push_back(cv::Point2f(cx, cy));
227 const std::vector<int>& faces,
228 const std::vector<cv::Point2f>& vertices) {
230 std::vector<double> areas;
232 if (faces.size() % 3 != 0) {
233 LOG_ERROR <<
"Faces array size must be multiple of 3";
237 size_t n_triangles = faces.size() / 3;
238 areas.reserve(n_triangles);
240 for (
size_t i = 0; i < n_triangles; ++i) {
243 int v1 = faces[idx + 1];
244 int v2 = faces[idx + 2];
246 if (v0 >= vertices.size() || v1 >= vertices.size() || v2 >= vertices.size()) {
248 areas.push_back(std::nan(
""));
252 cv::Point2f p0 = vertices[v0];
253 cv::Point2f p1 = vertices[v1];
254 cv::Point2f p2 = vertices[v2];
257 double area = 0.5 * std::abs(
258 (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y)
261 areas.push_back(area);
static std::vector< int > flipOrientation(const std::vector< int > &faces)
Flip triangle orientation Matches MATLAB: F = F(:, [1 3 2])
static std::vector< double > computeEdgeLengths(const std::vector< int > &faces, const std::vector< cv::Point2f > &vertices)
Compute edge lengths for all triangles Matches MATLAB: patchEdgeLengths(F, V)
static std::vector< int > filterByEdgeLength(const std::vector< int > &faces, const std::vector< cv::Point2f > &vertices, double max_edge_threshold)
Filter irregular triangles by edge length Matches MATLAB: F(EdgeLengthsMax > threshold,...
static std::vector< cv::Point2f > computeCentroids(const std::vector< int > &faces, const std::vector< cv::Point2f > &vertices)
Compute face centroids.
static std::vector< double > computeAreas(const std::vector< int > &faces, const std::vector< cv::Point2f > &vertices)
Compute face areas.
static std::vector< int > compute(const std::vector< cv::Point2f > &points)
Compute Delaunay triangulation of 2D points Matches MATLAB: DT = delaunayTriangulation(P)
Lightweight, dependency-free logging facility for CPPxDIC.
DataSerializer - Abstract base class for format-agnostic DIC data I/O.
CGAL::Delaunay_triangulation_2< K, Tds > Delaunay
CGAL::Triangulation_data_structure_2< Vb > Tds
CGAL::Exact_predicates_inexact_constructions_kernel K
CGAL::Triangulation_vertex_base_with_info_2< size_t, K > Vb