deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
utilities.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2014 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#include <deal.II/base/config.h>
14
16
17#ifdef DEAL_II_WITH_OPENCASCADE
18
20# include <deal.II/base/point.h>
22
24
25# include <IGESControl_Controller.hxx>
26# include <IGESControl_Reader.hxx>
27# include <IGESControl_Writer.hxx>
28# include <STEPControl_Controller.hxx>
29# include <STEPControl_Reader.hxx>
30# include <STEPControl_Writer.hxx>
31# include <TopExp_Explorer.hxx>
32# include <TopoDS.hxx>
33# include <TopoDS_Edge.hxx>
34# include <TopoDS_Face.hxx>
35# include <TopoDS_Shape.hxx>
36
37# include <cstdio>
38# include <iostream>
39# if DEAL_II_OPENCASCADE_VERSION_GTE(7, 0, 0)
40# include <Standard_Transient.hxx>
41# else
42# include <Handle_Standard_Transient.hxx>
43# endif
44
45# include <BRepAdaptor_Curve.hxx>
46# if DEAL_II_OPENCASCADE_VERSION_GTE(7, 6, 0)
47# include <BRepAlgoAPI_Section.hxx>
48# else
49# include <BRepAdaptor_HCompCurve.hxx>
50# include <BRepAdaptor_HCurve.hxx>
51# include <BRepAlgo_Section.hxx>
52# endif
53# include <BRepAdaptor_Surface.hxx>
54# include <BRepBndLib.hxx>
55# include <BRepBuilderAPI_MakeEdge.hxx>
56# include <BRepBuilderAPI_Sewing.hxx>
57# include <BRepBuilderAPI_Transform.hxx>
58# include <BRepMesh_IncrementalMesh.hxx>
59# include <BRepTools.hxx>
60# include <BRep_Builder.hxx>
61# include <GCPnts_AbscissaPoint.hxx>
62# include <GeomAPI_Interpolate.hxx>
63# include <GeomAPI_ProjectPointOnCurve.hxx>
64# include <GeomAPI_ProjectPointOnSurf.hxx>
65# include <GeomConvert_CompCurveToBSplineCurve.hxx>
66# include <GeomLProp_SLProps.hxx>
67# include <Geom_BoundedCurve.hxx>
68# include <Geom_Plane.hxx>
69# include <IntCurvesFace_ShapeIntersector.hxx>
70# include <Poly_Triangulation.hxx>
71# include <ShapeAnalysis_Surface.hxx>
72# include <StlAPI_Reader.hxx>
73# include <StlAPI_Writer.hxx>
74# include <TColStd_HSequenceOfTransient.hxx>
75# include <TColStd_SequenceOfTransient.hxx>
76# include <TColgp_HArray1OfPnt.hxx>
77# include <TopLoc_Location.hxx>
78# include <gp_Lin.hxx>
79# include <gp_Pnt.hxx>
80# include <gp_Vec.hxx>
81
82# include <algorithm>
83# include <vector>
84
85// OpenCASCADE defines a macro that creates class names. When building
86// modules, we don't #include any of the OpenCASCADE header files, and
87// we can't export macros, so the macro is not available. Re-declare
88// it here if it is not defined. (And if it is defined, we have a
89// problem: Apparently some header #include above is left in the file
90// by accident. Error out in that case so we get alerted to the
91// problem.)
92# ifdef DEAL_II_BUILDING_CXX20_MODULE
93# ifndef HANDLE
94# define Handle(ClassName) Handle_##ClassName
95# else
96# error \
97 "Some OpenCASCADE header file is apparently included even when building modules!"
98# endif
99# endif
100
101#endif
102
104
105#ifdef DEAL_II_WITH_OPENCASCADE
106
107namespace OpenCASCADE
108{
109 std::tuple<unsigned int, unsigned int, unsigned int>
110 count_elements(const TopoDS_Shape &shape)
111 {
112 TopExp_Explorer exp;
113 unsigned int n_faces = 0, n_edges = 0, n_vertices = 0;
114 for (exp.Init(shape, TopAbs_FACE); exp.More(); exp.Next(), ++n_faces)
115 {
116 }
117 for (exp.Init(shape, TopAbs_EDGE); exp.More(); exp.Next(), ++n_edges)
118 {
119 }
120 for (exp.Init(shape, TopAbs_VERTEX); exp.More(); exp.Next(), ++n_vertices)
121 {
122 }
123 return std::tuple<unsigned int, unsigned int, unsigned int>(n_faces,
124 n_edges,
125 n_vertices);
126 }
127
128 void
129 extract_geometrical_shapes(const TopoDS_Shape &shape,
130 std::vector<TopoDS_Face> &faces,
131 std::vector<TopoDS_Edge> &edges,
132 std::vector<TopoDS_Vertex> &vertices)
133 {
134 faces.resize(0);
135 edges.resize(0);
136 vertices.resize(0);
137
138 TopExp_Explorer exp;
139 for (exp.Init(shape, TopAbs_FACE); exp.More(); exp.Next())
140 {
141 faces.push_back(TopoDS::Face(exp.Current()));
142 }
143 for (exp.Init(shape, TopAbs_EDGE); exp.More(); exp.Next())
144 {
145 edges.push_back(TopoDS::Edge(exp.Current()));
146 }
147 for (exp.Init(shape, TopAbs_VERTEX); exp.More(); exp.Next())
148 {
149 vertices.push_back(TopoDS::Vertex(exp.Current()));
150 }
151 }
152
153
154 void
155 extract_compound_shapes(const TopoDS_Shape &shape,
156 std::vector<TopoDS_Compound> &compounds,
157 std::vector<TopoDS_CompSolid> &compsolids,
158 std::vector<TopoDS_Solid> &solids,
159 std::vector<TopoDS_Shell> &shells,
160 std::vector<TopoDS_Wire> &wires)
161 {
162 compounds.resize(0);
163 compsolids.resize(0);
164 solids.resize(0);
165 shells.resize(0);
166 wires.resize(0);
167
168 TopExp_Explorer exp;
169 for (exp.Init(shape, TopAbs_COMPOUND); exp.More(); exp.Next())
170 {
171 compounds.push_back(TopoDS::Compound(exp.Current()));
172 }
173 for (exp.Init(shape, TopAbs_COMPSOLID); exp.More(); exp.Next())
174 {
175 compsolids.push_back(TopoDS::CompSolid(exp.Current()));
176 }
177 for (exp.Init(shape, TopAbs_SOLID); exp.More(); exp.Next())
178 {
179 solids.push_back(TopoDS::Solid(exp.Current()));
180 }
181 for (exp.Init(shape, TopAbs_SHELL); exp.More(); exp.Next())
182 {
183 shells.push_back(TopoDS::Shell(exp.Current()));
184 }
185 for (exp.Init(shape, TopAbs_WIRE); exp.More(); exp.Next())
186 {
187 wires.push_back(TopoDS::Wire(exp.Current()));
188 }
189 }
190
191 template <int spacedim>
192 gp_Pnt
194 {
195 switch (spacedim)
196 {
197 case 1:
198 return gp_Pnt(p[0], 0, 0);
199 case 2:
200 return gp_Pnt(p[0], p[1], 0);
201 case 3:
202 return gp_Pnt(p[0], p[1], p[2]);
203 }
205 return {};
206 }
207
208 template <int spacedim>
210 point(const gp_Pnt &p, const double tolerance)
211 {
212 (void)tolerance;
213 switch (spacedim)
214 {
215 case 1:
216 Assert(std::abs(p.Y()) <= tolerance,
218 "Cannot convert OpenCASCADE point to 1d if p.Y() != 0."));
219 Assert(std::abs(p.Z()) <= tolerance,
221 "Cannot convert OpenCASCADE point to 1d if p.Z() != 0."));
222 return Point<spacedim>(p.X());
223 case 2:
224 Assert(std::abs(p.Z()) <= tolerance,
226 "Cannot convert OpenCASCADE point to 2d if p.Z() != 0."));
227 return Point<spacedim>(p.X(), p.Y());
228 case 3:
229 return Point<spacedim>(p.X(), p.Y(), p.Z());
230 }
232 return {};
233 }
234
235 template <int dim>
236 bool
238 const Point<dim> &p2,
239 const Tensor<1, dim> &direction,
240 const double tolerance)
241 {
242 const double rel_tol =
243 std::max(tolerance, std::max(p1.norm(), p2.norm()) * tolerance);
244 if (direction.norm() > 0.0)
245 return (p1 * direction < p2 * direction - rel_tol);
246 else
247 for (int d = dim; d >= 0; --d)
248 if (p1[d] < p2[d] - rel_tol)
249 return true;
250 else if (p2[d] < p1[d] - rel_tol)
251 return false;
252
253 // If we got here, for all d, none of the conditions above was
254 // satisfied. The two points are equal up to tolerance
255 return false;
256 }
257
258
259 TopoDS_Shape
260 read_IGES(const std::string &filename, const double scale_factor)
261 {
262 IGESControl_Reader reader;
263 IFSelect_ReturnStatus stat;
264 stat = reader.ReadFile(filename.c_str());
265 AssertThrow(stat == IFSelect_RetDone, ExcMessage("Error in reading file!"));
266
267 Standard_Boolean failsonly = Standard_False;
268 IFSelect_PrintCount mode = IFSelect_ItemsByEntity;
269 reader.PrintCheckLoad(failsonly, mode);
270
271 Standard_Integer nRoots = reader.TransferRoots();
272 // selects all IGES entities (including non visible ones) in the
273 // file and puts them into a list called MyList,
274
275 AssertThrow(nRoots > 0, ExcMessage("Read nothing from file."));
276
277 // Handle IGES Scale here.
278 gp_Pnt Origin;
279 gp_Trsf scale;
280 scale.SetScale(Origin, scale_factor);
281
282 TopoDS_Shape sh = reader.OneShape();
283 BRepBuilderAPI_Transform trans(sh, scale);
284
285 return trans.Shape(); // this is the actual translation
286 }
287
288 void
289 write_IGES(const TopoDS_Shape &shape, const std::string &filename)
290 {
291 IGESControl_Controller::Init();
292 IGESControl_Writer ICW("MM", 0);
293 Standard_Boolean ok = ICW.AddShape(shape);
294 AssertThrow(ok, ExcMessage("Failed to add shape to IGES controller."));
295 ICW.ComputeModel();
296 Standard_Boolean OK = ICW.Write(filename.c_str());
297 AssertThrow(OK, ExcMessage("Failed to write IGES file."));
298 }
299
300
301 TopoDS_Shape
302 read_STL(const std::string &filename)
303 {
304 StlAPI_Reader reader;
305 TopoDS_Shape shape;
306 reader.Read(shape, filename.c_str());
307 return shape;
308 }
309
310
311 void
312 write_STL(const TopoDS_Shape &shape,
313 const std::string &filename,
314 const double deflection,
315 const bool sew_different_faces,
316 const double sewer_tolerance,
317 const bool is_relative,
318 const double angular_deflection,
319 const bool in_parallel)
320 {
321 TopLoc_Location Loc;
322 std::vector<TopoDS_Vertex> vertices;
323 std::vector<TopoDS_Edge> edges;
324 std::vector<TopoDS_Face> faces;
325 OpenCASCADE::extract_geometrical_shapes(shape, faces, edges, vertices);
326 const bool mesh_is_present =
327 std::none_of(faces.begin(), faces.end(), [&Loc](const TopoDS_Face &face) {
328 Handle(Poly_Triangulation) theTriangulation =
329 BRep_Tool::Triangulation(face, Loc);
330 return theTriangulation.IsNull();
331 });
332 TopoDS_Shape shape_to_be_written = shape;
333 if (!mesh_is_present)
334 {
335 if (sew_different_faces)
336 {
337 BRepBuilderAPI_Sewing sewer(sewer_tolerance);
338 sewer.Add(shape_to_be_written);
339 sewer.Perform();
340 shape_to_be_written = sewer.SewedShape();
341 }
342 else
343 shape_to_be_written = shape;
344 // BRepMesh_IncrementalMesh automatically calls the perform method to
345 // create the triangulation which is stored in the argument
346 // `shape_to_be_written`.
347 BRepMesh_IncrementalMesh mesh_im(shape_to_be_written,
348 deflection,
349 is_relative,
350 angular_deflection,
351 in_parallel);
352 }
353
354 StlAPI_Writer writer;
355
356# if DEAL_II_OPENCASCADE_VERSION_GTE(6, 9, 0)
357 // opencascade versions 6.9.0 onwards return an error status
358 const auto error = writer.Write(shape_to_be_written, filename.c_str());
359
360 // which is a custom type between 6.9.0 and 7.1.0
361# if !DEAL_II_OPENCASCADE_VERSION_GTE(7, 2, 0)
362 AssertThrow(error == StlAPI_StatusOK,
363 ExcMessage("Error writing STL from shape."));
364# else
365 // and a boolean from version 7.2.0 onwards
366 AssertThrow(error == true, ExcMessage("Error writing STL from shape."));
367# endif
368
369# else
370
371 // for opencascade versions 6.8.0 and older the return value is void
372 writer.Write(shape_to_be_written, filename.c_str());
373# endif
374 }
375
376 TopoDS_Shape
377 read_STEP(const std::string &filename, const double scale_factor)
378 {
379 STEPControl_Reader reader;
380 IFSelect_ReturnStatus stat;
381 stat = reader.ReadFile(filename.c_str());
382 AssertThrow(stat == IFSelect_RetDone, ExcMessage("Error in reading file!"));
383
384 Standard_Boolean failsonly = Standard_False;
385 IFSelect_PrintCount mode = IFSelect_ItemsByEntity;
386 reader.PrintCheckLoad(failsonly, mode);
387
388 Standard_Integer nRoots = reader.TransferRoots();
389 // selects all IGES entities (including non visible ones) in the
390 // file and puts them into a list called MyList,
391
392 AssertThrow(nRoots > 0, ExcMessage("Read nothing from file."));
393
394 // Handle STEP Scale here.
395 gp_Pnt Origin;
396 gp_Trsf scale;
397 scale.SetScale(Origin, scale_factor);
398
399 TopoDS_Shape sh = reader.OneShape();
400 BRepBuilderAPI_Transform trans(sh, scale);
401
402 return trans.Shape(); // this is the actual translation
403 }
404
405 void
406 write_STEP(const TopoDS_Shape &shape, const std::string &filename)
407 {
408 STEPControl_Controller::Init();
409 STEPControl_Writer SCW;
410 IFSelect_ReturnStatus status;
411 status = SCW.Transfer(shape, STEPControl_AsIs);
412 AssertThrow(status == IFSelect_RetDone,
413 ExcMessage("Failed to add shape to STEP controller."));
414
415 status = SCW.Write(filename.c_str());
416
417 AssertThrow(status == IFSelect_RetDone,
418 ExcMessage("Failed to write translated shape to STEP file."));
419 }
420
421 double
422 get_shape_tolerance(const TopoDS_Shape &shape)
423 {
424 double tolerance = 0.0;
425
426 std::vector<TopoDS_Face> faces;
427 std::vector<TopoDS_Edge> edges;
428 std::vector<TopoDS_Vertex> vertices;
429
430 extract_geometrical_shapes(shape, faces, edges, vertices);
431
432 for (const auto &vertex : vertices)
433 tolerance = std::fmax(tolerance, BRep_Tool::Tolerance(vertex));
434
435 for (const auto &edge : edges)
436 tolerance = std::fmax(tolerance, BRep_Tool::Tolerance(edge));
437
438 for (const auto &face : faces)
439 tolerance = std::fmax(tolerance, BRep_Tool::Tolerance(face));
440
441
442 return tolerance;
443 }
444
445 TopoDS_Shape
446 intersect_plane(const TopoDS_Shape &in_shape,
447 const double c_x,
448 const double c_y,
449 const double c_z,
450 const double c,
451 const double /*tolerance*/)
452 {
453 Handle(Geom_Plane) plane = new Geom_Plane(c_x, c_y, c_z, c);
454# if DEAL_II_OPENCASCADE_VERSION_GTE(7, 6, 0)
455 BRepAlgoAPI_Section section(in_shape, plane);
456# else
457 BRepAlgo_Section section(in_shape, plane);
458# endif
459 TopoDS_Shape edges = section.Shape();
460 return edges;
461 }
462
463 TopoDS_Edge
464 join_edges(const TopoDS_Shape &in_shape, const double tolerance)
465 {
466 TopoDS_Edge out_shape;
467 const TopoDS_Shape &edges = in_shape;
468 std::vector<Handle_Geom_BoundedCurve> intersections;
469 TopLoc_Location L;
470 Standard_Real First;
471 Standard_Real Last;
472 gp_Pnt PIn(0.0, 0.0, 0.0);
473 gp_Pnt PFin(0.0, 0.0, 0.0);
474 gp_Pnt PMid(0.0, 0.0, 0.0);
475 TopExp_Explorer edgeExplorer(edges, TopAbs_EDGE);
476 TopoDS_Edge edge;
477 while (edgeExplorer.More())
478 {
479 edge = TopoDS::Edge(edgeExplorer.Current());
480 Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, L, First, Last);
481 intersections.push_back(Handle(Geom_BoundedCurve)::DownCast(curve));
482 edgeExplorer.Next();
483 }
484
485 // Now we build a single bspline out of all the geometrical
486 // curves, in Lexycographical order
487 unsigned int numIntersEdges = intersections.size();
488 Assert(numIntersEdges > 0, ExcMessage("No curves to process!"));
489
490 GeomConvert_CompCurveToBSplineCurve convert_bspline(intersections[0]);
491
492 bool check = false, one_added = true, one_failed = true;
493 std::vector<bool> added(numIntersEdges, false);
494 added[0] = true;
495 while (one_added == true)
496 {
497 one_added = false;
498 one_failed = false;
499 for (unsigned int i = 1; i < numIntersEdges; ++i)
500 if (added[i] == false)
501 {
502 Handle(Geom_Curve) curve = intersections[i];
503 Handle(Geom_BoundedCurve) bcurve =
504 Handle(Geom_BoundedCurve)::DownCast(curve);
505 check = convert_bspline.Add(bcurve, tolerance, false, true, 0);
506 if (check ==
507 false) // If we failed, try again with the reversed curve
508 {
509 curve->Reverse();
510 Handle(Geom_BoundedCurve) bcurve =
511 Handle(Geom_BoundedCurve)::DownCast(curve);
512 check =
513 convert_bspline.Add(bcurve, tolerance, false, true, 0);
514 }
515 one_failed = one_failed || (check == false);
516 one_added = one_added || (check == true);
517 added[i] = check;
518 }
519 }
520
521 Assert(one_failed == false,
522 ExcMessage("Joining some of the Edges failed."));
523
524 Handle(Geom_Curve) bspline = convert_bspline.BSplineCurve();
525
526 out_shape = BRepBuilderAPI_MakeEdge(bspline);
527 return out_shape;
528 }
529
530 template <int dim>
532 line_intersection(const TopoDS_Shape &in_shape,
533 const Point<dim> &origin,
534 const Tensor<1, dim> &direction,
535 const double tolerance)
536 {
537 // translating original Point<dim> to gp point
538
539 gp_Pnt P0 = point(origin);
540 gp_Ax1 gpaxis(P0,
541 gp_Dir(direction[0],
542 dim > 1 ? direction[1] : 0,
543 dim > 2 ? direction[2] : 0));
544 gp_Lin line(gpaxis);
545
546 // destination point
547 gp_Pnt Pproj(0.0, 0.0, 0.0);
548
549 // we prepare now the surface for the projection we get the whole
550 // shape from the iges model
551 IntCurvesFace_ShapeIntersector Inters;
552 Inters.Load(in_shape, tolerance);
553
554 // Keep in mind: PerformNearest sounds pretty but DOESN'T WORK!!!
555 // The closest point must be found by hand
556 Inters.Perform(line, -RealLast(), +RealLast());
557 Assert(Inters.IsDone(), ExcMessage("Could not project point."));
558
559 double minDistance = 1e7;
560 Point<dim> result;
561 for (int i = 0; i < Inters.NbPnt(); ++i)
562 {
563 const double distance = point(origin).Distance(Inters.Pnt(i + 1));
564 // cout<<"Point "<<i<<": "<<point(Inters.Pnt(i+1))<<" distance:
565 // "<<distance<<endl;
566 if (distance < minDistance)
567 {
568 minDistance = distance;
569 result = point<dim>(Inters.Pnt(i + 1));
570 }
571 }
572
573 return result;
574 }
575
576 template <int dim>
577 TopoDS_Edge
578 interpolation_curve(std::vector<Point<dim>> &curve_points,
579 const Tensor<1, dim> &direction,
580 const bool closed,
581 const double tolerance)
582 {
583 unsigned int n_vertices = curve_points.size();
584
585 if (direction * direction > 0)
586 {
587 std::sort(curve_points.begin(),
588 curve_points.end(),
589 [&](const Point<dim> &p1, const Point<dim> &p2) {
590 return OpenCASCADE::point_compare(p1,
591 p2,
592 direction,
593 tolerance);
594 });
595 }
596
597 // set up array of vertices
598 Handle(TColgp_HArray1OfPnt) vertices =
599 new TColgp_HArray1OfPnt(1, n_vertices);
600 for (unsigned int vertex = 0; vertex < n_vertices; ++vertex)
601 {
602 vertices->SetValue(vertex + 1, point(curve_points[vertex]));
603 }
604
605
606 GeomAPI_Interpolate bspline_generator(vertices, closed, tolerance);
607 bspline_generator.Perform();
608 Assert((bspline_generator.IsDone()),
609 ExcMessage("Interpolated bspline generation failed"));
610
611 Handle(Geom_BSplineCurve) bspline = bspline_generator.Curve();
612 TopoDS_Edge out_shape = BRepBuilderAPI_MakeEdge(bspline);
613 out_shape.Closed(closed);
614 return out_shape;
615 }
616
617
618
619 template <int spacedim>
620 std::vector<TopoDS_Edge>
622 const Triangulation<2, spacedim> &triangulation,
623 const Mapping<2, spacedim> &mapping)
624
625 {
626 // store maps from global vertex index to pairs of global face indices
627 // and from global face index to pairs of global vertex indices
628 std::map<unsigned int, std::pair<unsigned int, unsigned int>> vert_to_faces;
629 std::map<unsigned int, std::pair<unsigned int, unsigned int>> face_to_verts;
630 std::map<unsigned int, bool> visited_faces;
631 std::map<unsigned int, Point<spacedim>> vert_to_point;
632
633 unsigned int face_index;
634
635 for (const auto &cell : triangulation.active_cell_iterators())
636 for (const unsigned int f : GeometryInfo<2>::face_indices())
637 if (cell->face(f)->at_boundary())
638 {
639 // get global face and vertex indices
640 face_index = cell->face(f)->index();
641 const unsigned int v0 = cell->face(f)->vertex_index(0);
642 const unsigned int v1 = cell->face(f)->vertex_index(1);
643 face_to_verts[face_index].first = v0;
644 face_to_verts[face_index].second = v1;
645 visited_faces[face_index] = false;
646
647 // extract mapped vertex locations
648 const auto verts = mapping.get_vertices(cell);
649 vert_to_point[v0] = verts[GeometryInfo<2>::face_to_cell_vertices(
650 f, 0, true, false, false)];
651 vert_to_point[v1] = verts[GeometryInfo<2>::face_to_cell_vertices(
652 f, 1, true, false, false)];
653
654 // distribute indices into maps
655 if (vert_to_faces.find(v0) == vert_to_faces.end())
656 {
657 vert_to_faces[v0].first = face_index;
658 }
659 else
660 {
661 vert_to_faces[v0].second = face_index;
662 }
663 if (vert_to_faces.find(v1) == vert_to_faces.end())
664 {
665 vert_to_faces[v1].first = face_index;
666 }
667 else
668 {
669 vert_to_faces[v1].second = face_index;
670 }
671 }
672
673 // run through maps in an orderly fashion, i.e., through the
674 // boundary in one cycle and add points to pointlist.
675 std::vector<TopoDS_Edge> interpolation_curves;
676 bool finished = (face_to_verts.empty());
677 face_index = finished ? 0 : face_to_verts.begin()->first;
678
679 while (finished == false)
680 {
681 const unsigned int start_point_index = face_to_verts[face_index].first;
682 unsigned int point_index = start_point_index;
683
684 // point_index and face_index always run together
685 std::vector<Point<spacedim>> pointlist;
686 do
687 {
688 visited_faces[face_index] = true;
689 auto current_point = vert_to_point[point_index];
690 pointlist.push_back(current_point);
691
692 // Get next point
693 if (face_to_verts[face_index].first != point_index)
694 point_index = face_to_verts[face_index].first;
695 else
696 point_index = face_to_verts[face_index].second;
697
698 // Get next face
699 if (vert_to_faces[point_index].first != face_index)
700 face_index = vert_to_faces[point_index].first;
701 else
702 face_index = vert_to_faces[point_index].second;
703 }
704 while (point_index != start_point_index);
705
706 interpolation_curves.push_back(
707 interpolation_curve(pointlist, Tensor<1, spacedim>(), true));
708
709 finished = true;
710 for (const auto &f : visited_faces)
711 if (f.second == false)
712 {
713 face_index = f.first;
714 finished = false;
715 break;
716 }
717 }
718 return interpolation_curves;
719 }
720
721
722 template <int dim>
723 std::tuple<Point<dim>, TopoDS_Shape, double, double>
724 project_point_and_pull_back(const TopoDS_Shape &in_shape,
725 const Point<dim> &origin,
726 const double tolerance)
727 {
728 TopExp_Explorer exp;
729 gp_Pnt Pproj = point(origin);
730
731 double minDistance = 1e7;
732 gp_Pnt tmp_proj(0.0, 0.0, 0.0);
733
734 unsigned int counter = 0;
735 unsigned int face_counter = 0;
736
737 TopoDS_Shape out_shape;
738 double u = 0;
739 double v = 0;
740
741 for (exp.Init(in_shape, TopAbs_FACE); exp.More(); exp.Next())
742 {
743 TopoDS_Face face = TopoDS::Face(exp.Current());
744
745 // the projection function needs a surface, so we obtain the
746 // surface upon which the face is defined
747 Handle(Geom_Surface) SurfToProj = BRep_Tool::Surface(face);
748
749 ShapeAnalysis_Surface projector(SurfToProj);
750 gp_Pnt2d proj_params = projector.ValueOfUV(point(origin), tolerance);
751
752 SurfToProj->D0(proj_params.X(), proj_params.Y(), tmp_proj);
753
754 double distance = point<dim>(tmp_proj).distance(origin);
755 if (distance < minDistance)
756 {
757 minDistance = distance;
758 Pproj = tmp_proj;
759 out_shape = face;
760 u = proj_params.X();
761 v = proj_params.Y();
762 ++counter;
763 }
764 ++face_counter;
765 }
766
767 // face counter tells us if the shape contained faces: if it does, there is
768 // no need to loop on edges. Even if the closest point lies on the boundary
769 // of a parametric surface, we need in fact to retain the face and both u
770 // and v, if we want to use this method to retrieve the surface normal
771 if (face_counter == 0)
772 for (exp.Init(in_shape, TopAbs_EDGE); exp.More(); exp.Next())
773 {
774 TopoDS_Edge edge = TopoDS::Edge(exp.Current());
775 if (!BRep_Tool::Degenerated(edge))
776 {
777 TopLoc_Location L;
778 Standard_Real First;
779 Standard_Real Last;
780
781 // the projection function needs a Curve, so we obtain the
782 // curve upon which the edge is defined
783 Handle(Geom_Curve) CurveToProj =
784 BRep_Tool::Curve(edge, L, First, Last);
785
786 GeomAPI_ProjectPointOnCurve Proj(point(origin), CurveToProj);
787 unsigned int num_proj_points = Proj.NbPoints();
788 if ((num_proj_points > 0) && (Proj.LowerDistance() < minDistance))
789 {
790 minDistance = Proj.LowerDistance();
791 Pproj = Proj.NearestPoint();
792 out_shape = edge;
793 u = Proj.LowerDistanceParameter();
794 ++counter;
795 }
796 }
797 }
798
799 Assert(counter > 0, ExcMessage("Could not find projection points."));
800 return std::tuple<Point<dim>, TopoDS_Shape, double, double>(
801 point<dim>(Pproj), out_shape, u, v);
802 }
803
804
805 template <int dim>
807 closest_point(const TopoDS_Shape &in_shape,
808 const Point<dim> &origin,
809 const double tolerance)
810 {
811 std::tuple<Point<dim>, TopoDS_Shape, double, double> ref =
812 project_point_and_pull_back(in_shape, origin, tolerance);
813 return std::get<0>(ref);
814 }
815
816 std::tuple<Point<3>, Tensor<1, 3>, double, double>
817 closest_point_and_differential_forms(const TopoDS_Shape &in_shape,
818 const Point<3> &origin,
819 const double tolerance)
820
821 {
822 std::tuple<Point<3>, TopoDS_Shape, double, double> shape_and_params =
823 project_point_and_pull_back(in_shape, origin, tolerance);
824
825 TopoDS_Shape &out_shape = std::get<1>(shape_and_params);
826 double &u = std::get<2>(shape_and_params);
827 double &v = std::get<3>(shape_and_params);
828
829 // just a check here: the number of faces in out_shape must be 1, otherwise
830 // something is wrong
831 std::tuple<unsigned int, unsigned int, unsigned int> numbers =
832 count_elements(out_shape);
833 (void)numbers;
834
835 Assert(
836 std::get<0>(numbers) > 0,
838 "Could not find normal: the shape containing the closest point has 0 faces."));
839 Assert(
840 std::get<0>(numbers) < 2,
842 "Could not find normal: the shape containing the closest point has more than 1 face."));
843
844
845 TopExp_Explorer exp;
846 exp.Init(out_shape, TopAbs_FACE);
847 TopoDS_Face face = TopoDS::Face(exp.Current());
848 return push_forward_and_differential_forms(face, u, v, tolerance);
849 }
850
851 template <int dim>
853 push_forward(const TopoDS_Shape &in_shape, const double u, const double v)
854 {
855 switch (in_shape.ShapeType())
856 {
857 case TopAbs_FACE:
858 {
859 BRepAdaptor_Surface surf(TopoDS::Face(in_shape));
860 return point<dim>(surf.Value(u, v));
861 }
862 case TopAbs_EDGE:
863 {
864 BRepAdaptor_Curve curve(TopoDS::Edge(in_shape));
865 return point<dim>(curve.Value(u));
866 }
867 default:
868 Assert(false, ExcUnsupportedShape());
869 }
870 return {};
871 }
872
873 std::tuple<Point<3>, Tensor<1, 3>, double, double>
874 push_forward_and_differential_forms(const TopoDS_Face &face,
875 const double u,
876 const double v,
877 const double /*tolerance*/)
878 {
879 Handle(Geom_Surface) SurfToProj = BRep_Tool::Surface(face);
880 GeomLProp_SLProps props(SurfToProj, u, v, 1, 1e-7);
881 gp_Pnt Value = props.Value();
882 Assert(props.IsNormalDefined(), ExcMessage("Normal is not well defined!"));
883 gp_Dir Normal = props.Normal();
884 Assert(props.IsCurvatureDefined(),
885 ExcMessage("Curvature is not well defined!"));
886 Standard_Real Min_Curvature = props.MinCurvature();
887 Standard_Real Max_Curvature = props.MaxCurvature();
888 Tensor<1, 3> normal = Point<3>(Normal.X(), Normal.Y(), Normal.Z());
889
890 // In the case your manifold changes from convex to concave or vice-versa
891 // the normal could jump from "inner" to "outer" normal.
892 // However, you should be able to change the normal sense preserving
893 // the manifold orientation:
894 if (face.Orientation() == TopAbs_REVERSED)
895 {
896 normal *= -1;
897 Min_Curvature *= -1;
898 Max_Curvature *= -1;
899 }
900
901 return std::tuple<Point<3>, Tensor<1, 3>, double, double>(point<3>(Value),
902 normal,
903 Min_Curvature,
904 Max_Curvature);
905 }
906
907
908
909 template <int spacedim>
910 void
911 create_triangulation(const TopoDS_Face &face,
913 {
914 BRepAdaptor_Surface surf(face);
915 const double u0 = surf.FirstUParameter();
916 const double u1 = surf.LastUParameter();
917 const double v0 = surf.FirstVParameter();
918 const double v1 = surf.LastVParameter();
919
920 std::vector<CellData<2>> cells;
921 std::vector<Point<spacedim>> vertices;
922 SubCellData t;
923
924 vertices.push_back(point<spacedim>(surf.Value(u0, v0)));
925 vertices.push_back(point<spacedim>(surf.Value(u1, v0)));
926 vertices.push_back(point<spacedim>(surf.Value(u0, v1)));
927 vertices.push_back(point<spacedim>(surf.Value(u1, v1)));
928
929 CellData<2> cell;
930 for (unsigned int i = 0; i < 4; ++i)
931 cell.vertices[i] = i;
932
933 cells.push_back(cell);
934 tria.create_triangulation(vertices, cells, t);
935 }
936
937// We don't build the .inst file if deal.II isn't configured
938// with GMSH, but doxygen doesn't know that and tries to find that
939// file anyway for parsing -- which then of course it fails on. So
940// exclude the following from doxygen consideration.
941# ifndef DOXYGEN
942# include "opencascade/utilities.inst"
943# endif
944
945} // namespace OpenCASCADE
946
947
948#endif
949
Abstract base class for mapping classes.
Definition mapping.h:318
virtual boost::container::small_vector< Point< spacedim >, ReferenceCells::max_n_vertices< dim >() > get_vertices(const typename Triangulation< dim, spacedim >::cell_iterator &cell) const
Definition point.h:111
numbers::NumberTraits< Number >::real_type norm() const
virtual void create_triangulation(const std::vector< Point< spacedim > > &vertices, const std::vector< CellData< dim > > &cells, const SubCellData &subcelldata)
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
Point< 2 > first
Definition grid_out.cc:4639
const unsigned int v0
const unsigned int v1
IteratorRange< active_cell_iterator > active_cell_iterators() const
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcUnsupportedShape()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
TopoDS_Edge interpolation_curve(std::vector< Point< dim > > &curve_points, const Tensor< 1, dim > &direction=Tensor< 1, dim >(), const bool closed=false, const double tolerance=1e-7)
Definition utilities.cc:578
std::tuple< Point< 3 >, Tensor< 1, 3 >, double, double > push_forward_and_differential_forms(const TopoDS_Face &face, const double u, const double v, const double tolerance=1e-7)
Definition utilities.cc:874
void extract_compound_shapes(const TopoDS_Shape &shape, std::vector< TopoDS_Compound > &compounds, std::vector< TopoDS_CompSolid > &compsolids, std::vector< TopoDS_Solid > &solids, std::vector< TopoDS_Shell > &shells, std::vector< TopoDS_Wire > &wires)
Definition utilities.cc:155
Point< dim > push_forward(const TopoDS_Shape &in_shape, const double u, const double v)
Definition utilities.cc:853
std::tuple< unsigned int, unsigned int, unsigned int > count_elements(const TopoDS_Shape &shape)
Definition utilities.cc:110
void write_STEP(const TopoDS_Shape &shape, const std::string &filename)
Definition utilities.cc:406
std::tuple< Point< 3 >, Tensor< 1, 3 >, double, double > closest_point_and_differential_forms(const TopoDS_Shape &in_shape, const Point< 3 > &origin, const double tolerance=1e-7)
Definition utilities.cc:817
void extract_geometrical_shapes(const TopoDS_Shape &shape, std::vector< TopoDS_Face > &faces, std::vector< TopoDS_Edge > &edges, std::vector< TopoDS_Vertex > &vertices)
Definition utilities.cc:129
TopoDS_Edge join_edges(const TopoDS_Shape &in_shape, const double tolerance=1e-7)
Definition utilities.cc:464
TopoDS_Shape read_STEP(const std::string &filename, const double scale_factor=1e-3)
Definition utilities.cc:377
bool point_compare(const Point< dim > &p1, const Point< dim > &p2, const Tensor< 1, dim > &direction=Tensor< 1, dim >(), const double tolerance=1e-10)
Definition utilities.cc:237
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition utilities.cc:210
Point< dim > closest_point(const TopoDS_Shape &in_shape, const Point< dim > &origin, const double tolerance=1e-7)
Definition utilities.cc:807
std::tuple< Point< dim >, TopoDS_Shape, double, double > project_point_and_pull_back(const TopoDS_Shape &in_shape, const Point< dim > &origin, const double tolerance=1e-7)
Definition utilities.cc:724
Point< dim > line_intersection(const TopoDS_Shape &in_shape, const Point< dim > &origin, const Tensor< 1, dim > &direction, const double tolerance=1e-7)
Definition utilities.cc:532
void write_STL(const TopoDS_Shape &shape, const std::string &filename, const double deflection, const bool sew_different_faces=false, const double sewer_tolerance=1e-6, const bool is_relative=false, const double angular_deflection=0.5, const bool in_parallel=false)
Definition utilities.cc:312
void create_triangulation(const TopoDS_Face &face, Triangulation< 2, spacedim > &tria)
Definition utilities.cc:911
TopoDS_Shape read_STL(const std::string &filename)
Definition utilities.cc:302
TopoDS_Shape intersect_plane(const TopoDS_Shape &in_shape, const double c_x, const double c_y, const double c_z, const double c, const double tolerance=1e-7)
Definition utilities.cc:446
std::vector< TopoDS_Edge > create_curves_from_triangulation_boundary(const Triangulation< 2, spacedim > &triangulation, const Mapping< 2, spacedim > &mapping=StaticMappingQ1< 2, spacedim >::mapping)
Definition utilities.cc:621
double get_shape_tolerance(const TopoDS_Shape &shape)
Definition utilities.cc:422
void write_IGES(const TopoDS_Shape &shape, const std::string &filename)
Definition utilities.cc:289
TopoDS_Shape read_IGES(const std::string &filename, const double scale_factor=1e-3)
Definition utilities.cc:260
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
std_cxx26::inplace_vector< unsigned int, ReferenceCells::max_n_vertices< structdim >()> vertices
Definition cell_data.h:84
static unsigned int face_to_cell_vertices(const unsigned int face, const unsigned int vertex, const bool face_orientation=true, const bool face_flip=false, const bool face_rotation=false)
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > face_indices()