Line data Source code
1 : // The libMesh Finite Element Library.
2 : // Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 :
4 : // This library is free software; you can redistribute it and/or
5 : // modify it under the terms of the GNU Lesser General Public
6 : // License as published by the Free Software Foundation; either
7 : // version 2.1 of the License, or (at your option) any later version.
8 :
9 : // This library is distributed in the hope that it will be useful,
10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : // Lesser General Public License for more details.
13 :
14 : // You should have received a copy of the GNU Lesser General Public
15 : // License along with this library; if not, write to the Free Software
16 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 :
18 : // Local includes
19 : #include "libmesh/edge_edge2.h"
20 : #include "libmesh/face_tri3.h"
21 : #include "libmesh/enum_io_package.h"
22 : #include "libmesh/enum_order.h"
23 :
24 : namespace libMesh
25 : {
26 :
27 :
28 :
29 : // ------------------------------------------------------------
30 : // Tri3 class static member initializations
31 : const int Tri3::num_nodes;
32 : const int Tri3::nodes_per_side;
33 :
34 : #ifdef LIBMESH_ENABLE_AMR
35 :
36 : const Real Tri3::_embedding_matrix[Tri3::num_children][Tri3::num_nodes][Tri3::num_nodes] =
37 : {
38 : // embedding matrix for child 0
39 : {
40 : // 0 1 2
41 : {1.0, 0.0, 0.0}, // 0
42 : {0.5, 0.5, 0.0}, // 1
43 : {0.5, 0.0, 0.5} // 2
44 : },
45 :
46 : // embedding matrix for child 1
47 : {
48 : // 0 1 2
49 : {0.5, 0.5, 0.0}, // 0
50 : {0.0, 1.0, 0.0}, // 1
51 : {0.0, 0.5, 0.5} // 2
52 : },
53 :
54 : // embedding matrix for child 2
55 : {
56 : // 0 1 2
57 : {0.5, 0.0, 0.5}, // 0
58 : {0.0, 0.5, 0.5}, // 1
59 : {0.0, 0.0, 1.0} // 2
60 : },
61 :
62 : // embedding matrix for child 3
63 : {
64 : // 0 1 2
65 : {0.5, 0.5, 0.0}, // 0
66 : {0.0, 0.5, 0.5}, // 1
67 : {0.5, 0.0, 0.5} // 2
68 : }
69 : };
70 :
71 : #endif
72 :
73 :
74 :
75 : // ------------------------------------------------------------
76 : // Tri3 class member functions
77 :
78 21144252 : bool Tri3::is_vertex(const unsigned int libmesh_dbg_var(n)) const
79 : {
80 736704 : libmesh_assert_not_equal_to (n, invalid_uint);
81 21144252 : return true;
82 : }
83 :
84 0 : bool Tri3::is_edge(const unsigned int) const
85 : {
86 0 : return false;
87 : }
88 :
89 0 : bool Tri3::is_face(const unsigned int) const
90 : {
91 0 : return false;
92 : }
93 :
94 732546 : bool Tri3::is_node_on_side(const unsigned int n,
95 : const unsigned int s) const
96 : {
97 23328 : libmesh_assert_less (s, n_sides());
98 23328 : return std::find(std::begin(side_nodes_map[s]),
99 732546 : std::end(side_nodes_map[s]),
100 732546 : n) != std::end(side_nodes_map[s]);
101 : }
102 :
103 : std::vector<unsigned>
104 35262 : Tri3::nodes_on_side(const unsigned int s) const
105 : {
106 2326 : libmesh_assert_less(s, n_sides());
107 68198 : return {std::begin(side_nodes_map[s]), std::end(side_nodes_map[s])};
108 : }
109 :
110 : std::vector<unsigned>
111 3093 : Tri3::nodes_on_edge(const unsigned int e) const
112 : {
113 3093 : return nodes_on_side(e);
114 : }
115 :
116 38080136 : Order Tri3::default_order() const
117 : {
118 38080136 : return FIRST;
119 : }
120 :
121 3416 : bool Tri3::has_invertible_map(Real tol) const
122 : {
123 3416 : return this->volume() > tol;
124 : }
125 :
126 8088008 : std::unique_ptr<Elem> Tri3::build_side_ptr (const unsigned int i)
127 : {
128 8088008 : return this->simple_build_side_ptr<Edge2, Tri3>(i);
129 : }
130 :
131 :
132 :
133 618009 : void Tri3::build_side_ptr (std::unique_ptr<Elem> & side,
134 : const unsigned int i)
135 : {
136 618009 : this->simple_build_side_ptr<Tri3>(side, i, EDGE2);
137 618009 : }
138 :
139 :
140 :
141 135744 : void Tri3::connectivity(const unsigned int libmesh_dbg_var(sf),
142 : const IOPackage iop,
143 : std::vector<dof_id_type> & conn) const
144 : {
145 11312 : libmesh_assert_less (sf, this->n_sub_elem());
146 11312 : libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);
147 :
148 135744 : switch (iop)
149 : {
150 135744 : case TECPLOT:
151 : {
152 135744 : conn.resize(4);
153 147056 : conn[0] = this->node_id(0)+1;
154 135744 : conn[1] = this->node_id(1)+1;
155 135744 : conn[2] = this->node_id(2)+1;
156 135744 : conn[3] = this->node_id(2)+1;
157 135744 : return;
158 : }
159 :
160 0 : case VTK:
161 : {
162 0 : conn.resize(3);
163 0 : conn[0] = this->node_id(0);
164 0 : conn[1] = this->node_id(1);
165 0 : conn[2] = this->node_id(2);
166 0 : return;
167 : }
168 :
169 0 : default:
170 0 : libmesh_error_msg("Unsupported IO package " << iop);
171 : }
172 : }
173 :
174 :
175 :
176 :
177 :
178 :
179 839 : Point Tri3::true_centroid () const
180 : {
181 839 : return Elem::vertex_average();
182 : }
183 :
184 859706 : Real Tri3::volume () const
185 : {
186 : // This specialization is good for non-Lagrange mappings too! Even
187 : // with differing vertex weights we've still got a p=1 planar face.
188 :
189 : // 3-node triangles have the following formula for computing the area
190 859706 : return 0.5 * cross_norm(point(1) - point(0),
191 891985 : point(2) - point(0));
192 : }
193 :
194 :
195 :
196 0 : std::pair<Real, Real> Tri3::min_and_max_angle() const
197 : {
198 0 : Point v10 ( this->point(1) - this->point(0) );
199 0 : Point v20 ( this->point(2) - this->point(0) );
200 0 : Point v21 ( this->point(2) - this->point(1) );
201 :
202 : const Real
203 0 : len_10=v10.norm(),
204 0 : len_20=v20.norm(),
205 0 : len_21=v21.norm();
206 :
207 : const Real
208 0 : theta0=std::acos(( v10*v20)/len_10/len_20),
209 0 : theta1=std::acos((-v10*v21)/len_10/len_21),
210 0 : theta2=libMesh::pi - theta0 - theta1
211 : ;
212 :
213 0 : libmesh_assert_greater (theta0, 0.);
214 0 : libmesh_assert_greater (theta1, 0.);
215 0 : libmesh_assert_greater (theta2, 0.);
216 :
217 : return std::make_pair(std::min(theta0, std::min(theta1,theta2)),
218 0 : std::max(theta0, std::max(theta1,theta2)));
219 : }
220 :
221 2154954 : bool Tri3::contains_point (const Point & p, Real tol) const
222 : {
223 : // See "Barycentric Technique" section at
224 : // http://www.blackpawn.com/texts/pointinpoly for details.
225 :
226 : // Compute vectors
227 378828 : Point v0 = this->point(1) - this->point(0);
228 189414 : Point v1 = this->point(2) - this->point(0);
229 189414 : Point v2 = p - this->point(0);
230 :
231 : // Compute dot products
232 2154954 : Real dot00 = v0 * v0;
233 189414 : Real dot01 = v0 * v1;
234 189414 : Real dot02 = v0 * v2;
235 2154954 : Real dot11 = v1 * v1;
236 189414 : Real dot12 = v1 * v2;
237 :
238 : // Out of plane check
239 2828622 : if (std::abs(triple_product(v2, v0, v1)) / std::max(dot00, dot11) > tol)
240 6 : return false;
241 :
242 : // Compute barycentric coordinates
243 2154741 : Real invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
244 2154741 : Real u = (dot11 * dot02 - dot01 * dot12) * invDenom;
245 2154741 : Real v = (dot00 * dot12 - dot01 * dot02) * invDenom;
246 :
247 : // Check if point is in triangle
248 2154741 : return (u > -tol) && (v > -tol) && (u + v < 1 + tol);
249 : }
250 :
251 : BoundingBox
252 13197810 : Tri3::loose_bounding_box () const
253 : {
254 13197810 : return Elem::loose_bounding_box();
255 : }
256 :
257 :
258 7008 : void Tri3::permute(unsigned int perm_num)
259 : {
260 624 : libmesh_assert_less (perm_num, 3);
261 :
262 14016 : for (unsigned int i = 0; i != perm_num; ++i)
263 : {
264 7008 : swap3nodes(0,1,2);
265 6384 : swap3neighbors(0,1,2);
266 : }
267 7008 : }
268 :
269 :
270 3132 : void Tri3::flip(BoundaryInfo * boundary_info)
271 : {
272 120 : libmesh_assert(boundary_info);
273 :
274 3132 : swap2nodes(0,1);
275 120 : swap2neighbors(1,2);
276 3132 : swap2boundarysides(1,2,boundary_info);
277 3132 : swap2boundaryedges(1,2,boundary_info);
278 3132 : }
279 :
280 :
281 : ElemType
282 402220 : Tri3::side_type (const unsigned int libmesh_dbg_var(s)) const
283 : {
284 34808 : libmesh_assert_less (s, 3);
285 402220 : return EDGE2;
286 : }
287 :
288 :
289 : Point
290 426 : Tri3::side_vertex_average_normal(const unsigned int s) const
291 : {
292 12 : libmesh_assert_less (s, 3);
293 450 : const Point side_t = this->point(side_nodes_map[s][1]) -
294 426 : this->point(side_nodes_map[s][0]);
295 426 : const unsigned int another_side = s > 1 ? 0 : s + 1;
296 450 : const Point other_side_t = this->point(side_nodes_map[another_side][1]) -
297 426 : this->point(side_nodes_map[another_side][0]);
298 414 : const Point pointing_up = side_t.cross(other_side_t);
299 414 : const Point v = side_t.cross(pointing_up);
300 426 : return v.unit();
301 : }
302 :
303 :
304 : } // namespace libMesh
|