8#ifndef model_MeshBoundarySegment_cpp_
9#define model_MeshBoundarySegment_cpp_
28 for(
const auto& face :
faces)
30 if(face->periodicFacePair.second)
32 temp+=face->periodicFacePair.first;
44 throw std::runtime_error(
"EMPY FACE CONTAINER");
47 for(
const auto& face : fcs)
49 temp+=face->outNormal();
51 const double tempNorm(
temp.norm());
60 for(
const auto& face :
faces)
62 temp+=face->outNormal(
k);
64 const double tempNorm(
temp.norm());
65 return tempNorm>FLT_EPSILON? (
temp/tempNorm).
eval() : VectorDim::Zero();
74 FiniteLineSegmentType(p0,
p1)
75 ,faces(FaceContainerType({face}))
76 ,outNormal(getBoundaryNormal(faces))
84 FiniteLineSegmentType(p0,
p1)
86 ,outNormal(getBoundaryNormal(
faces))
92 using SectionKey=std::pair<int,std::vector<size_t>>;
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)
105 for(
const auto& incidence :
f.second->perimeter)
107 scale=std::max(scale,incidence.source()->position.norm());
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)
113 auto found=distances.find(
vertex->key);
114 if(found==distances.end())
117 if(std::abs(value)<=tolerance)
121 found=distances.emplace(
vertex->key,value).first;
123 return found->second;
125 std::set<size_t> coincidentFaces;
126 for(
const auto&
f : region.children)
128 bool coincident=
true;
129 for(
const auto& incidence :
f.second->perimeter)
131 coincident=coincident && distance(incidence.source())==0;
135 coincidentFaces.insert(
f.first);
148 arcs[{
a,
b}].insert(face);
150 for(
const auto&
f : region.children)
152 const auto& face=*
f.second;
153 std::set<SectionKey> roots;
154 bool containsEdge=
false;
155 for(
const auto& incidence : face.perimeter)
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};
170 points.emplace(v1,sink->position);
172 const auto other=incidence.otherFace(region.key).face.lock();
175 if(!(coincidentFaces.count(
f.first) && coincidentFaces.count(other->key)))
180 else if((d0<0 && d1>0) || (d0>0 && d1<0))
182 const SectionKey
key{1,incidence.edge->key};
195 addArc(*roots.begin(),*roots.rbegin(),&face);
197 else if(roots.size()>2)
199 throw std::runtime_error(
"Grain section requires convex faces: more than two crossings");
208 std::map<SectionKey,std::vector<SectionKey>>
adjacency;
209 for(
const auto& arc : arcs)
211 adjacency[arc.first.first].push_back(arc.first.second);
212 adjacency[arc.first.second].push_back(arc.first.first);
219 for(
const auto& entry : adjacency)
221 if(entry.second.size()!=2)
224 const Vector
base=
points.at(arcs.begin()->first.first);
227 for(
const auto& node : adjacency)
235 throw std::runtime_error(
"Grain section has a non-manifold intersection vertex");
241 std::set<Arc> visited;
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)
249 throw std::runtime_error(
"Grain section repeats an arc before closure");
255 if(visited.size()!=arcs.size())
257 throw std::runtime_error(
"Grain section has multiple contours; convex grain required");
259 Vector
area=Vector::Zero();
261 for(
const auto& segment :
result)
263 area+=(segment->P0-
origin).cross(segment->P1-origin);
268 for(
auto& segment :
result)
270 segment=std::make_shared<MeshBoundarySegment<dim>>(segment->P1,segment->P0,segment->faces);
276 while(merged &&
result.size()>2)
281 const size_t next=(
k+1)%
result.size();
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()))
288 result[
k]=std::make_shared<MeshBoundarySegment<dim>>(
a->P0,
b->P1,
a->faces);
304 const size_t& regionID,
const Plane<dim>& plane)
306 const auto section=grainSection<dim>(
mesh.polyhedralMesh().region(regionID),plane);
307 this->assign(section.begin(),section.end());
314 std::set<const MeshBoundarySegment<dim>*>
temp;
316 for(
const auto& seg : *
this)
320 temp.insert(seg.get());
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)
VectorDim periodicShift() const
Polyhedron< dim, dim-1 > PlanarMeshFaceType
function int_R syms a b c u real f
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