Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
MeshBoundarySegment.cpp
Go to the documentation of this file.
1/* This file is part of MoDELib, the Mechanics Of Defects Evolution Library.
2 *
3 *
4 * MoDELib is distributed without any warranty under the
5 * GNU General Public License (GPL) v2 <http://www.gnu.org/licenses/>.
6 */
7
8#ifndef model_MeshBoundarySegment_cpp_
9#define model_MeshBoundarySegment_cpp_
10
11#include <cfloat>
12#include <set>
13#include <Eigen/Dense>
14#include <FiniteLineSegment.h>
15
16#include <MeshModule.h>
17#include <PolyhedralMesh.h>
18#include <limits>
19#include <algorithm>
20
21namespace model
22{
23
24 template <int dim>
26 {
27 VectorDim temp(VectorDim::Zero());
28 for(const auto& face : faces)
29 {
30 if(face->periodicFacePair.second)
31 {
32 temp+=face->periodicFacePair.first;
33 }
34 }
35 return temp;
36 }
37
38
39 template <int dim>
40 typename MeshBoundarySegment<dim>::VectorDim MeshBoundarySegment<dim>::getBoundaryNormal(const typename MeshBoundarySegment<dim>::FaceContainerType& fcs)
41 {
42 if(fcs.size()==0)
43 {
44 throw std::runtime_error("EMPY FACE CONTAINER");
45 }
46 typename MeshBoundarySegment<dim>::VectorDim temp(MeshBoundarySegment<dim>::VectorDim::Zero());
47 for(const auto& face : fcs)
48 {
49 temp+=face->outNormal();
50 }
51 const double tempNorm(temp.norm());
52 return tempNorm>FLT_EPSILON? (temp/tempNorm).eval() : VectorDim::Zero();
53 }
54
55template <int dim>
57{
58
60 for(const auto& face : faces)
61 {
62 temp+=face->outNormal(k);
63 }
64 const double tempNorm(temp.norm());
65 return tempNorm>FLT_EPSILON? (temp/tempNorm).eval() : VectorDim::Zero();
66}
67
68
69
70 template <int dim>
73 const typename MeshBoundarySegment<dim>::PlanarMeshFaceType* const face) :
74 /* init */ FiniteLineSegmentType(p0,p1)
75 /* init */,faces(FaceContainerType({face}))
76 /* init */,outNormal(getBoundaryNormal(faces))
77 {
78 }
79
80 template <int dim>
83 const typename MeshBoundarySegment<dim>::FaceContainerType& faces_in) :
84 /* init */ FiniteLineSegmentType(p0,p1)
85 /* init */,faces(faces_in)
86 /* init */,outNormal(getBoundaryNormal(faces))
87 {
88 }
89
90 namespace
91 {
92 using SectionKey=std::pair<int,std::vector<size_t>>;
93 template<int dim>
94 BoundingMeshSegments<dim> grainSection(const Polyhedron<dim,dim>& region,const Plane<dim>& plane)
95 {
96 using Vector=Eigen::Matrix<double,dim,1>;
98 using Arc=std::pair<SectionKey,SectionKey>;
99 std::map<std::vector<size_t>,double> distances;
100 std::map<SectionKey,Vector> points;
101 std::map<Arc,Faces> arcs;
102 double scale=plane.P.norm();
103 for(const auto& f : region.children)
104 {
105 for(const auto& incidence : f.second->perimeter)
106 {
107 scale=std::max(scale,incidence.source()->position.norm());
108 }
109 }
110 const double tolerance=std::max(double(FLT_EPSILON),64*std::numeric_limits<double>::epsilon()*scale);
111 auto distance=[&](const std::shared_ptr<Polyhedron<dim,0>>& vertex)
112 {
113 auto found=distances.find(vertex->key);
114 if(found==distances.end())
115 {
116 double value=(vertex->position-plane.P).dot(plane.unitNormal);
117 if(std::abs(value)<=tolerance)
118 {
119 value=0;
120 }
121 found=distances.emplace(vertex->key,value).first;
122 }
123 return found->second;
124 };
125 std::set<size_t> coincidentFaces;
126 for(const auto& f : region.children)
127 {
128 bool coincident=true;
129 for(const auto& incidence : f.second->perimeter)
130 {
131 coincident=coincident && distance(incidence.source())==0;
132 }
133 if(coincident)
134 {
135 coincidentFaces.insert(f.first);
136 }
137 }
138 auto addArc=[&](SectionKey a,SectionKey b,const Polyhedron<dim,dim-1>* face)
139 {
140 if(a==b)
141 {
142 return;
143 }
144 if(b<a)
145 {
146 std::swap(a,b);
147 }
148 arcs[{a,b}].insert(face);
149 };
150 for(const auto& f : region.children)
151 {
152 const auto& face=*f.second;
153 std::set<SectionKey> roots;
154 bool containsEdge=false;
155 for(const auto& incidence : face.perimeter)
156 {
157 const auto source=incidence.source();
158 const auto sink=incidence.sink();
159 const double d0=distance(source);
160 const double d1=distance(sink);
161 const SectionKey v0{0,source->key};
162 const SectionKey v1{0,sink->key};
163 if(d0==0)
164 {
165 points.emplace(v0,source->position);
166 roots.insert(v0);
167 }
168 if(d0==0 && d1==0)
169 {
170 points.emplace(v1,sink->position);
171 containsEdge=true;
172 const auto other=incidence.otherFace(region.key).face.lock();
173 // An edge internal to coplanar face patches is not part
174 // of the perimeter of the grain section.
175 if(!(coincidentFaces.count(f.first) && coincidentFaces.count(other->key)))
176 {
177 addArc(v0,v1,&face);
178 }
179 }
180 else if((d0<0 && d1>0) || (d0>0 && d1<0))
181 {
182 const SectionKey key{1,incidence.edge->key};
183 // Shared edge identity gives a single computed position.
184 if(!points.count(key))
185 {
186 points.emplace(key,source->position+(d0/(d0-d1))*(sink->position-source->position));
187 }
188 roots.insert(key);
189 }
190 }
191 if(!containsEdge)
192 {
193 if(roots.size()==2)
194 {
195 addArc(*roots.begin(),*roots.rbegin(),&face);
196 }
197 else if(roots.size()>2)
198 {
199 throw std::runtime_error("Grain section requires convex faces: more than two crossings");
200 }
201 }
202 }
204 if(arcs.empty())
205 {
206 return result;
207 }
208 std::map<SectionKey,std::vector<SectionKey>> adjacency;
209 for(const auto& arc : arcs)
210 {
211 adjacency[arc.first.first].push_back(arc.first.second);
212 adjacency[arc.first.second].push_back(arc.first.first);
213 }
214 // A tangent edge is a degenerate section, not an open polygon.
215 if(arcs.size()==1)
216 {
217 return result;
218 }
219 for(const auto& entry : adjacency)
220 {
221 if(entry.second.size()!=2)
222 {
223 // A chain of collinear on-plane edges can also be tangent.
224 const Vector base=points.at(arcs.begin()->first.first);
225 const Vector direction=points.at(arcs.begin()->first.second)-base;
226 bool collinear=true;
227 for(const auto& node : adjacency)
228 {
229 collinear=collinear && direction.cross(points.at(node.first)-base).norm()<=tolerance*direction.norm();
230 }
231 if(collinear)
232 {
233 return result;
234 }
235 throw std::runtime_error("Grain section has a non-manifold intersection vertex");
236 }
237 }
238 const SectionKey start=adjacency.begin()->first;
239 SectionKey current=start;
240 SectionKey previous;
241 std::set<Arc> visited;
242 do
243 {
244 const auto& neighbors=adjacency.at(current);
245 const SectionKey next=neighbors[0]==previous ? neighbors[1] : neighbors[0];
246 const Arc arc=std::minmax(current,next);
247 if(!visited.insert(arc).second)
248 {
249 throw std::runtime_error("Grain section repeats an arc before closure");
250 }
251 result.emplace_back(std::make_shared<MeshBoundarySegment<dim>>(points.at(current),points.at(next),arcs.at(arc)));
252 previous=current;
253 current=next;
254 } while(current!=start);
255 if(visited.size()!=arcs.size())
256 {
257 throw std::runtime_error("Grain section has multiple contours; convex grain required");
258 }
259 Vector area=Vector::Zero();
260 const Vector origin=result.front()->P0;
261 for(const auto& segment : result)
262 {
263 area+=(segment->P0-origin).cross(segment->P1-origin);
264 }
265 if(area.dot(plane.unitNormal)<0)
266 {
267 std::reverse(result.begin(),result.end());
268 for(auto& segment : result)
269 {
270 segment=std::make_shared<MeshBoundarySegment<dim>>(segment->P1,segment->P0,segment->faces);
271 }
272 }
273 // Remove only subdivision points on the same straight supported arc.
274 // Connectivity above, never endpoint proximity, determines the walk.
275 bool merged=true;
276 while(merged && result.size()>2)
277 {
278 merged=false;
279 for(size_t k=0;k<result.size();++k)
280 {
281 const size_t next=(k+1)%result.size();
282 const auto a=result[k];
283 const auto b=result[next];
284 const Vector u=a->P1-a->P0;
285 const Vector v=b->P1-b->P0;
286 if(a->faces==b->faces && u.dot(v)>0 && u.cross(v).norm()<=tolerance*(u.norm()+v.norm()))
287 {
288 result[k]=std::make_shared<MeshBoundarySegment<dim>>(a->P0,b->P1,a->faces);
289 result.erase(result.begin()+next);
290 merged=true;
291 break;
292 }
293 }
294 }
295 return result;
296 }
297 }
298
299 template<int dim>
301
302 template<int dim>
304 const size_t& regionID,const Plane<dim>& plane)
305 {
306 const auto section=grainSection<dim>(mesh.polyhedralMesh().region(regionID),plane);
307 this->assign(section.begin(),section.end());
308 }
309
310 /**********************************************************************/
311 template <int dim>
312 std::set<const MeshBoundarySegment<dim>*> BoundingMeshSegments<dim>::containingSegments(const VectorDim& P) const
313 {
314 std::set<const MeshBoundarySegment<dim>*> temp;
315
316 for(const auto& seg : *this)
317 {
318 if(seg->contains(P))
319 {
320 temp.insert(seg.get());
321 }
322 }
323 return temp;
324 }
325
326 /**********************************************************************/
327 template <int dim>
329 {
330 return containingSegments(P).size();
331 }
332
333 /**********************************************************************/
334 template <int dim>
339
340 template <int dim>
345
346 template class MeshBoundarySegment<3>;
347 template struct BoundingMeshSegments<3>;
348
349}
350#endif
Class template representing a straight line at the intersection of PlanarMeshFaces.
Eigen::Matrix< double, dim, 1 > VectorDim
std::set< const Polyhedron< dim, dim-1 > * > FaceContainerType
VectorDim regionBoundaryNormal(const int &k) const
const FaceContainerType faces
MeshBoundarySegment(const VectorDim &p0, const VectorDim &p1, const PlanarMeshFaceType *const face)
Polyhedron< dim, dim-1 > PlanarMeshFaceType
function int_R syms a b c u real f
Definition int_R.m:4
a
Definition int_R.m:14
b
Definition int_R.m:16
auto eval(const std::shared_ptr< T > &t)
Eigen::Matrix< double, dim, 1 > VectorDim
bool contains(const VectorDim &P) const
const BoundingMeshSegments< dim > & boundingBoxSegments() const
std::set< const MeshBoundarySegment< dim > * > containingSegments(const VectorDim &P) const
enum finddirectionresult collinear
REAL u[4]
vertex p1
int k
newbad key
REAL * vertex
Definition triangle.cpp:542
vertex temp
REAL area
result
int current
REAL v[4]