#include #include #include #include "occ_edge.hpp" #include "occ_face.hpp" #include "occgeom.hpp" namespace netgen { OCCFace::OCCFace(TopoDS_Shape dshape) : tface(dshape.TShape()), face(TopoDS::Face(dshape)) { BRepGProp::LinearProperties(face, props); bbox = ::netgen::GetBoundingBox(face); surface = BRep_Tool::Surface(face); shape_analysis = new ShapeAnalysis_Surface( surface ); tolerance = BRep_Tool::Tolerance( face ); } size_t OCCFace::GetNBoundaries() const { return 0; } size_t OCCFace::GetHash() const { return reinterpret_cast(tface.get()); } Point<3> OCCFace::GetCenter() const { return occ2ng( props.CentreOfMass() ); } Array OCCFace::GetBoundary(const Mesh& mesh) const { auto & geom = dynamic_cast(*mesh.GetGeometry()); auto n_edges = geom.edge_map.size(); constexpr int UNUSED = 0; constexpr int FORWARD = 1; constexpr int REVERSED = 2; constexpr int BOTH = 3; Array edge_orientation(n_edges); edge_orientation = UNUSED; Array curve_on_face[BOTH]; curve_on_face[FORWARD].SetSize(n_edges); curve_on_face[REVERSED].SetSize(n_edges); Array edge_on_face[BOTH]; edge_on_face[FORWARD].SetSize(n_edges); edge_on_face[REVERSED].SetSize(n_edges); for(auto edge_ : GetEdges(face)) { auto edge = TopoDS::Edge(edge_); if(geom.edge_map.count(edge.TShape())==0) continue; auto edgenr = geom.edge_map[edge.TShape()]; auto & orientation = edge_orientation[edgenr]; double s0, s1; auto cof = BRep_Tool::CurveOnSurface (edge, face, s0, s1); if(edge.Orientation() == TopAbs_FORWARD) { curve_on_face[FORWARD][edgenr] = cof; orientation += FORWARD; edge_on_face[FORWARD][edgenr] = edge; } if(edge.Orientation() == TopAbs_REVERSED) { curve_on_face[REVERSED][edgenr] = cof; orientation += REVERSED; edge_on_face[REVERSED][edgenr] = edge; } if(orientation > BOTH) throw Exception("have edge more than twice in face " + ToString(nr) + " " + properties.GetName() + ", orientation: " + ToString(orientation)); } Array boundary; for (auto seg : mesh.LineSegments()) { auto edgenr = seg.epgeominfo[0].edgenr; auto orientation = edge_orientation[edgenr]; if(orientation == UNUSED) continue; for(const auto ORIENTATION : {FORWARD, REVERSED}) { if((orientation & ORIENTATION) == 0) continue; // auto cof = curve_on_face[ORIENTATION][edgenr]; auto edge = edge_on_face[ORIENTATION][edgenr]; OCCEdge gedge(edge); double s0, s1; auto cof = BRep_Tool::CurveOnSurface (edge, face, s0, s1); double s[2] = { seg.epgeominfo[0].dist, seg.epgeominfo[1].dist }; // dist is in [0,1], map parametrization to [s0, s1] s[0] = s0 + s[0]*(s1-s0); s[1] = s0 + s[1]*(s1-s0); // fixes normal-vector roundoff problem when endpoint is cone-tip double delta = s[1]-s[0]; s[0] += 1e-10*delta; s[1] -= 1e-10*delta; for(auto i : Range(2)) { auto uv = cof->Value(s[i]); seg.epgeominfo[i].u = uv.X(); seg.epgeominfo[i].v = uv.Y(); } if(ORIENTATION == REVERSED) { swap(seg[0], seg[1]); swap(seg.epgeominfo[0].dist, seg.epgeominfo[1].dist); swap(seg.epgeominfo[0].u, seg.epgeominfo[1].u); swap(seg.epgeominfo[0].v, seg.epgeominfo[1].v); } boundary.Append(seg); } } return boundary; } PointGeomInfo OCCFace::Project(Point<3>& p) const { auto suval = shape_analysis->ValueOfUV(ng2occ(p), tolerance); double u,v; suval.Coord(u, v); p = occ2ng(surface->Value( u, v )); PointGeomInfo gi; gi.trignum = nr+1; gi.u = u; gi.v = v; return gi; } bool OCCFace::ProjectPointGI(Point<3>& p_, PointGeomInfo& gi) const { double u = gi.u; double v = gi.v; auto p = ng2occ(p_); auto x = surface->Value (u,v); if (p.SquareDistance(x) <= sqr(PROJECTION_TOLERANCE)) return true; gp_Vec du, dv; surface->D1(u,v,x,du,dv); int count = 0; gp_Pnt xold; gp_Vec n; double det, lambda, mu; do { count++; n = du^dv; det = Det3 (n.X(), du.X(), dv.X(), n.Y(), du.Y(), dv.Y(), n.Z(), du.Z(), dv.Z()); if (det < 1e-15) return false; lambda = Det3 (n.X(), p.X()-x.X(), dv.X(), n.Y(), p.Y()-x.Y(), dv.Y(), n.Z(), p.Z()-x.Z(), dv.Z())/det; mu = Det3 (n.X(), du.X(), p.X()-x.X(), n.Y(), du.Y(), p.Y()-x.Y(), n.Z(), du.Z(), p.Z()-x.Z())/det; u += lambda; v += mu; xold = x; surface->D1(u,v,x,du,dv); } while (xold.SquareDistance(x) > sqr(PROJECTION_TOLERANCE) && count < 50); // (*testout) << "FastProject count: " << count << endl; if (count == 50) return false; p_ = occ2ng(x); return true; } Point<3> OCCFace::GetPoint(const PointGeomInfo& gi) const { return occ2ng(surface->Value( gi.u, gi.v )); } void OCCFace::CalcEdgePointGI(const GeometryEdge& edge, double t, EdgePointGeomInfo& egi) const { throw Exception(ToString("not implemented") + __FILE__ + ":" + ToString(__LINE__)); } Box<3> OCCFace::GetBoundingBox() const { return bbox; } double OCCFace::GetCurvature(const PointGeomInfo& gi) const { throw Exception(ToString("not implemented") + __FILE__ + ":" + ToString(__LINE__)); } void OCCFace::RestrictH(Mesh& mesh, const MeshingParameters& mparam) const { throw Exception(ToString("not implemented") + __FILE__ + ":" + ToString(__LINE__)); } Vec<3> OCCFace::GetNormal(const Point<3>& p, const PointGeomInfo* gi) const { PointGeomInfo gi_; if(gi==nullptr) { auto p_ = p; gi_ = Project(p_); gi = &gi_; } gp_Pnt pnt; gp_Vec du, dv; surface->D1(gi->u,gi->v,pnt,du,dv); auto n = Cross (occ2ng(du), occ2ng(dv)); n.Normalize(); if (face.Orientation() == TopAbs_REVERSED) n *= -1; return n; } }