Code_TYMPAN  4.4.0
Industrial site acoustic simulation
cgal_tools.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) <2012-2024> <EDF-DTG> <FRANCE>
3  * This file is part of Code_TYMPAN (R).
4  * Code_TYMPAN (R) is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * Code_TYMPAN (R) is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  * See the GNU General Public License for more details.
12  * You should have received a copy of the GNU General Public License along
13  * with Code_TYMPAN (R). If not, see <https://www.gnu.org/licenses/>.
14  */
15 
25 #include <cassert>
26 #include <algorithm>
27 #include <functional>
28 
29 #include "cgal_tools.h"
30 
31 namespace tympan
32 {
33 
34 CGAL_Plane to_cgal(const OPlan& oplan)
35 {
37  CGAL_Vector3 n(to_cgal(oplan.rframe._vecK));
38  return CGAL_Plane(o, n);
39 }
40 
42 {
43  return v / sqrt(v.squared_length());
44 }
45 
46 std::deque<CGAL_Point3> build_box(float w, float h, CGAL_Point3 pta, CGAL_Point3 ptb)
47 {
48  // AB vector
49  CGAL_Vector3 pta_ptb(pta, ptb);
50  // We need to build a plane containing pt A and pt B. A third point is needed.
51  CGAL_Point3 some_point(0, 1, 0); // have a try (Y axis)
52  // If AB vector and Asome_point vectors are colinear, use X axis instead of Y axis
53  if (CGAL::cross_product(pta_ptb, CGAL_Vector3(pta, some_point)) == CGAL::NULL_VECTOR)
54  some_point = CGAL_Point3(1, 0, 0);
55  // Build a plane with pt A, pt B and the arbitrary point and compute the orthogonal vector
56  CGAL_Vector3 ortho = normalize(CGAL::orthogonal_vector(pta, ptb, some_point));
57  // Compute another orthogonal vector
58  CGAL_Vector3 ortho2 = CGAL::cross_product(normalize(pta_ptb), ortho);
59  // Build the face containing pt A (add 2 perpendicular unit vectors respectively multiplied by
60  // w/2 and h/2 since the face dimension is l x h)
61  std::deque<CGAL_Point3> vertices;
62  vertices.push_back(pta - ortho * h / 2 + ortho2 * w / 2); // orig
63  vertices.push_back(pta - ortho * h / 2 + ortho2 * w / 2 + pta_ptb); // x
64  vertices.push_back(pta - ortho * h / 2 - ortho2 * w / 2); // y
65  vertices.push_back(pta + ortho * h / 2 + ortho2 * w / 2); // z
66  return vertices;
67 }
68 
69 void intersection_report(std::deque<size_t>* intersected, CGAL_Triangles::iterator start_index,
70  const CGAL_TBox& a, const CGAL_TBox& b)
71 {
72  // here we know the 2 boxes intersect, but we don't know for sure that the triangle of
73  // box a intersects with box b. Make sure it is the case before inserting the triangle
74  if (CGAL::do_intersect(*a.handle(), b.bbox()))
75  {
76  intersected->push_back(a.handle() - start_index);
77  }
78 }
79 
80 // This implementation is inspired from http://doc.cgal.org/4.4/Box_intersection_d/index.html
81 // (see parts "4 Minimal Example for Intersecting Boxes" and
82 // "5 Example for Finding Intersecting 3D Triangles")
83 std::deque<size_t> intersected_triangles(CGAL_Triangles& triangle_soup, std::deque<CGAL_Point3> query_box,
84  float length, float width, float height)
85 {
86  std::deque<CGAL_TBox> boxes;
87  // Put the triangles of the scene (triangle soup) in iso-oriented bounded boxes
88  for (CGAL_Triangles::iterator it = triangle_soup.begin(); it != triangle_soup.end(); it++)
89  {
90  boxes.push_back(CGAL_TBox(it->bbox(), it));
91  }
92  // Create a triangle whose bounding box will have the dimensions of the "query" box,
93  // choosing 3 nodes of the box as the triangle nodes (works because CGAL bounding box is
94  // iso-oriented)
95  CGAL_Triangles query_triangle;
96  query_triangle.push_back(CGAL_Triangle(query_box[0], query_box[1], query_box[2]));
97  std::deque<CGAL_TBox> query_tboxes;
98  CGAL::Bbox_3 box = query_triangle.begin()->bbox();
99  // Make sure the new query box has the same dimensions as "query" OBox2
100 #ifndef NDEBUG
101  double epsilon = 0.0001;
102  double x_dim = abs(box.xmax() - box.xmin());
103  double y_dim = abs(box.ymax() - box.ymin());
104  double z_dim = abs(box.zmax() - box.zmin());
105 #endif
106  assert(abs(x_dim - length) < epsilon &&
107  "The dimension X of CGAL query box doesn't match query parameter.");
108  assert(abs(y_dim - width) < epsilon && "The dimension Y CGAL query box doesn't match query parameter.");
109  assert(abs(z_dim - height) < epsilon &&
110  "The dimension Z of CGAL query box doesn't match query parameter.");
111  query_tboxes.push_back(CGAL_TBox(box, query_triangle.begin()));
112  // Compute intersection between the triangles from the triangle soup and the box
113  // from the query.
114  // "intersected" will contain the indices of the triangles of the triangle soup
115  // that intersect with the triangle of the query deque.
116  std::deque<size_t> intersected;
117  // use currying to specify container and triangle start index from here and therefore
118  // avoid using global variables (these variables must be accessible from the callback function,
119  // but CGAL::box_intersection_d requires a callback function that only deals with 2 boxes).
120  auto cgal_callback = std::bind(intersection_report, &intersected, triangle_soup.begin(),
121  std::placeholders::_1, std::placeholders::_2);
122  CGAL::box_intersection_d(boxes.begin(), boxes.end(), query_tboxes.begin(), query_tboxes.end(),
123  cgal_callback);
124  // remove duplicates (first order the triangle ids since std::unique only works on
125  // an ordered container)
126  std::sort(intersected.begin(), intersected.end());
127  auto last = std::unique(intersected.begin(), intersected.end());
128  intersected.erase(last, intersected.end());
129  return intersected;
130 }
131 
132 /* **** class PolygonTriangulator **** */
133 
135 {
136  assert(poly.size() > 2);
137  assert(poly.is_simple() && "The polygon need to be simple - no 8 shape");
138  unsigned i = 0; // index of the current ve
139  BOOST_FOREACH (const CGAL_Point2& current, poly.container())
140  {
141  Vertex_handle current_vh = cdt.insert(current);
142  current_vh->info() = VertexInfo(i);
143  poly_vh.push_back(current_vh);
144  if (i > 0)
145  {
146  cdt.insert_constraint(poly_vh[i - 1], poly_vh[i]);
147  }
148  ++i;
149  }
150  // Closes the polygon
151  cdt.insert_constraint(poly_vh[--i], poly_vh[0]);
152 } // PolygonTriangulator::PolygonTriangulator()
153 
154 PolygonTriangulator::~PolygonTriangulator() {} // PolygonTriangulator::~PolygonTriangulator()
155 
157 {
158  assert(poly_vh.size() == poly.size() && "Inconsistency btw points and vertices vectors.");
159  // Let the checked access std exception trigger for out-of-bound indices
160  return poly_vh.at(i);
161 }
162 
163 void PolygonTriangulator::exportTriangles(std::deque<PolygonTriangulator::Triangle>& triangles) const
164 {
165  assert(triangles.size() == 0 && "triangles output arguments expected to be empty");
166  for (CDT::Finite_faces_iterator it = cdt.finite_faces_begin(); it != cdt.finite_faces_end(); ++it)
167  {
168  // Extract a representative inner point
169  CGAL_Point2 center = CGAL::centroid(cdt.triangle(it));
170  // Test whether it is inside the polygon
171  switch (poly.bounded_side(center))
172  {
173  case CGAL::ON_UNBOUNDED_SIDE:
174  case CGAL::ON_BOUNDARY: // this is the degenerate case of a flat triangle
175  continue;
176  case CGAL::ON_BOUNDED_SIDE:
177  triangles.push_back(cdt.triangle(it)); // `it` is a Face_handle
178  break;
179  }
180  }
181 }
182 
183 void PolygonTriangulator::exportTrianglesIndices(std::deque<Tri_indices>& triangles) const
184 {
185 
186  assert(triangles.size() == 0 && "triangles output arguments expected to be empty");
187  for (CDT::Finite_faces_iterator it = cdt.finite_faces_begin(); it != cdt.finite_faces_end(); ++it)
188  {
189  // Extract a representative inner point
190  CGAL_Point2 center = CGAL::centroid(cdt.triangle(it));
191  // Test whether it is inside the polygon
192  switch (poly.bounded_side(center))
193  {
194  case CGAL::ON_UNBOUNDED_SIDE:
195  case CGAL::ON_BOUNDARY: // this is the degenerate case of a flat triangle
196  continue;
197  case CGAL::ON_BOUNDED_SIDE:
198  Tri_indices tri;
199  for (unsigned i = 0; i < 3; ++i)
200  {
201  tri[i] = it->vertex(i)->info().i;
202  }
203  triangles.push_back(tri);
204  break;
205  }
206  }
207 }
208 
209 } // namespace tympan
Utilities to ease (and wrap) use of CGAL.
Plan defined by its equation : ax+by+cz+d=0.
Definition: plan.h:31
ORepere3D rframe
Definition: plan.h:333
OVector3D _vecK
Vector K for the Z axis.
Definition: 3d.h:1337
OPoint3D _origin
The origin point.
Definition: 3d.h:1331
PolygonTriangulator(const CGAL_Polygon &poly_)
Constructor from a CGAL_Polygon.
Definition: cgal_tools.cpp:134
const Vertex_handle & vertex_handle(unsigned i) const
Return the ith vertex handle.
Definition: cgal_tools.cpp:156
virtual ~PolygonTriangulator()
Destructor.
Definition: cgal_tools.cpp:154
const CGAL_Polygon & poly
Reference to the CGAL_Polygon to triangulate.
Definition: cgal_tools.h:203
CDT::Vertex_handle Vertex_handle
Definition: cgal_tools.h:158
boost::array< unsigned, 3 > Tri_indices
Definition: cgal_tools.h:164
void exportTrianglesIndices(std::deque< Tri_indices > &triangles) const
Exports the triangles inside the polygon.
Definition: cgal_tools.cpp:183
void exportTriangles(std::deque< CDT::Triangle > &triangles) const
Exports the triangles inside the polygon.
Definition: cgal_tools.cpp:163
Vertex_handles_container poly_vh
Polygon vertex handles.
Definition: cgal_tools.h:202
CGAL_Vector3 normalize(CGAL_Vector3 v)
normalize vector v
Definition: cgal_tools.cpp:41
CGAL::Triangle_3< CGAL_Gt > CGAL_Triangle
Definition: cgal_tools.h:65
CGAL_Plane to_cgal(const OPlan &oplan)
Convert a OPlan to CGAL_Plane.
Definition: cgal_tools.cpp:34
CGAL::Point_3< CGAL_Gt > CGAL_Point3
Definition: cgal_tools.h:60
CGAL::Vector_3< CGAL_Gt > CGAL_Vector3
Definition: cgal_tools.h:62
CGAL::Point_2< CGAL_Gt > CGAL_Point2
Definition: cgal_tools.h:59
CGAL::Box_intersection_d::Box_with_handle_d< double, 3, CGAL_Triangles::iterator > CGAL_TBox
Definition: cgal_tools.h:67
std::deque< CGAL_Triangle > CGAL_Triangles
Definition: cgal_tools.h:66
std::deque< CGAL_Point3 > build_box(float w, float h, CGAL_Point3 pta, CGAL_Point3 ptb)
return 4 points defining a 3D parallelepiped
Definition: cgal_tools.cpp:46
CGAL::Plane_3< CGAL_Gt > CGAL_Plane
Definition: cgal_tools.h:64
CGAL::Polygon_2< CGAL_Gt > CGAL_Polygon
Definition: cgal_tools.h:63
void intersection_report(std::deque< size_t > *intersected, CGAL_Triangles::iterator start_index, const CGAL_TBox &a, const CGAL_TBox &b)
Definition: cgal_tools.cpp:69
std::deque< size_t > intersected_triangles(CGAL_Triangles &triangle_soup, std::deque< CGAL_Point3 > query_box, float length, float width, float height)
Find the triangles from triangle_soup that are intersected by the 3D box including the points of quer...
Definition: cgal_tools.cpp:83