2023-07-31 03:13:56 +05:00
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
|
2021-11-28 20:14:41 +05:00
|
|
|
#include <BRepGProp.hxx>
|
|
|
|
#include <BRep_Tool.hxx>
|
|
|
|
#include <GeomAPI_ProjectPointOnCurve.hxx>
|
2023-02-13 19:57:53 +05:00
|
|
|
#include <BRepLProp_SLProps.hxx>
|
2021-11-28 20:14:41 +05:00
|
|
|
|
2023-07-31 03:13:56 +05:00
|
|
|
#pragma clang diagnostic pop
|
|
|
|
|
2021-11-28 20:14:41 +05:00
|
|
|
#include "occ_edge.hpp"
|
|
|
|
#include "occ_face.hpp"
|
|
|
|
#include "occgeom.hpp"
|
|
|
|
|
|
|
|
namespace netgen
|
|
|
|
{
|
|
|
|
OCCFace::OCCFace(TopoDS_Shape dshape)
|
2022-08-19 15:51:39 +05:00
|
|
|
: face(TopoDS::Face(dshape))
|
2021-11-28 20:14:41 +05:00
|
|
|
{
|
2022-03-28 23:34:22 +05:00
|
|
|
BRepGProp::SurfaceProperties (dshape, props);
|
2021-11-28 20:14:41 +05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Point<3> OCCFace::GetCenter() const
|
|
|
|
{
|
|
|
|
return occ2ng( props.CentreOfMass() );
|
|
|
|
}
|
|
|
|
|
|
|
|
Array<Segment> OCCFace::GetBoundary(const Mesh& mesh) const
|
|
|
|
{
|
|
|
|
auto & geom = dynamic_cast<OCCGeometry&>(*mesh.GetGeometry());
|
|
|
|
|
2022-11-15 16:58:36 +05:00
|
|
|
auto n_edges = geom.GetNEdges();
|
2021-11-28 20:14:41 +05:00
|
|
|
constexpr int UNUSED = 0;
|
|
|
|
constexpr int FORWARD = 1;
|
|
|
|
constexpr int REVERSED = 2;
|
|
|
|
constexpr int BOTH = 3;
|
|
|
|
|
|
|
|
Array<int> edge_orientation(n_edges);
|
|
|
|
edge_orientation = UNUSED;
|
|
|
|
|
|
|
|
Array<Handle(Geom2d_Curve)> curve_on_face[BOTH];
|
|
|
|
curve_on_face[FORWARD].SetSize(n_edges);
|
|
|
|
curve_on_face[REVERSED].SetSize(n_edges);
|
|
|
|
|
|
|
|
Array<TopoDS_Edge> edge_on_face[BOTH];
|
|
|
|
edge_on_face[FORWARD].SetSize(n_edges);
|
|
|
|
edge_on_face[REVERSED].SetSize(n_edges);
|
|
|
|
|
2023-08-16 21:01:07 +05:00
|
|
|
// In case the face is INTERNAL, we need to orient it to FORWARD to get proper orientation for the edges
|
|
|
|
// (relative to the face) otherwise, all edges are also INTERNAL
|
|
|
|
auto oriented_face = TopoDS_Face(face);
|
|
|
|
if(oriented_face.Orientation() == TopAbs_INTERNAL)
|
|
|
|
oriented_face.Orientation(TopAbs_FORWARD);
|
|
|
|
|
|
|
|
for(auto edge_ : GetEdges(oriented_face))
|
2021-11-28 20:14:41 +05:00
|
|
|
{
|
|
|
|
auto edge = TopoDS::Edge(edge_);
|
2022-11-15 16:58:36 +05:00
|
|
|
auto edgenr = geom.GetEdge(edge).nr;
|
2021-11-28 20:14:41 +05:00
|
|
|
auto & orientation = edge_orientation[edgenr];
|
|
|
|
double s0, s1;
|
2023-08-16 21:01:07 +05:00
|
|
|
auto cof = BRep_Tool::CurveOnSurface (edge, oriented_face, s0, s1);
|
2023-06-05 14:24:52 +05:00
|
|
|
if(edge.Orientation() == TopAbs_FORWARD || edge.Orientation() == TopAbs_INTERNAL)
|
2021-11-28 20:14:41 +05:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2023-06-05 14:24:52 +05:00
|
|
|
if(edge.Orientation() == TopAbs_INTERNAL)
|
|
|
|
{
|
|
|
|
// add reversed edge
|
|
|
|
auto r_edge = TopoDS::Edge(edge.Reversed());
|
2023-08-16 21:01:07 +05:00
|
|
|
auto cof = BRep_Tool::CurveOnSurface (r_edge, oriented_face, s0, s1);
|
2023-06-05 14:24:52 +05:00
|
|
|
curve_on_face[REVERSED][edgenr] = cof;
|
|
|
|
orientation += REVERSED;
|
|
|
|
edge_on_face[REVERSED][edgenr] = r_edge;
|
|
|
|
}
|
2021-11-28 20:14:41 +05:00
|
|
|
|
|
|
|
if(orientation > BOTH)
|
|
|
|
throw Exception("have edge more than twice in face " + ToString(nr) + " " + properties.GetName() + ", orientation: " + ToString(orientation));
|
|
|
|
}
|
|
|
|
|
|
|
|
Array<Segment> 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];
|
|
|
|
double s0, s1;
|
|
|
|
auto cof = BRep_Tool::CurveOnSurface (edge, face, s0, s1);
|
|
|
|
|
|
|
|
double s[2] = { seg.epgeominfo[0].dist, seg.epgeominfo[1].dist };
|
|
|
|
|
2021-11-29 20:20:24 +05:00
|
|
|
// dist is in [0,1], map parametrization to [s0, s1]
|
2021-11-29 20:01:55 +05:00
|
|
|
s[0] = s0 + s[0]*(s1-s0);
|
|
|
|
s[1] = s0 + s[1]*(s1-s0);
|
|
|
|
|
2021-11-29 20:20:24 +05:00
|
|
|
// fixes normal-vector roundoff problem when endpoint is cone-tip
|
2021-11-28 20:14:41 +05:00
|
|
|
double delta = s[1]-s[0];
|
|
|
|
s[0] += 1e-10*delta;
|
|
|
|
s[1] -= 1e-10*delta;
|
|
|
|
|
|
|
|
for(auto i : Range(2))
|
|
|
|
{
|
2023-02-13 19:57:53 +05:00
|
|
|
// take uv from CurveOnSurface as start value but project again for better accuracy
|
|
|
|
// (cof->Value yields wrong values (outside of surface) for complicated faces
|
2021-11-28 20:14:41 +05:00
|
|
|
auto uv = cof->Value(s[i]);
|
2023-02-13 19:57:53 +05:00
|
|
|
PointGeomInfo gi;
|
|
|
|
gi.u = uv.X();
|
|
|
|
gi.v = uv.Y();
|
|
|
|
Point<3> pproject = mesh[seg[i]];
|
|
|
|
ProjectPointGI(pproject, gi);
|
|
|
|
seg.epgeominfo[i].u = gi.u;
|
|
|
|
seg.epgeominfo[i].v = gi.v;
|
2021-11-28 20:14:41 +05:00
|
|
|
}
|
|
|
|
|
2023-01-16 16:01:17 +05:00
|
|
|
bool do_swap = ORIENTATION == REVERSED;
|
|
|
|
if(seg.epgeominfo[1].dist < seg.epgeominfo[0].dist)
|
|
|
|
do_swap = !do_swap;
|
|
|
|
|
|
|
|
if(do_swap)
|
2021-11-28 20:14:41 +05:00
|
|
|
{
|
|
|
|
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
|
|
|
|
{
|
2022-10-16 16:08:27 +05:00
|
|
|
/*
|
2022-10-10 19:36:07 +05:00
|
|
|
static Timer t("OCCFace::ProjectPointGI");
|
|
|
|
RegionTimer rt(t);
|
2022-10-16 16:08:27 +05:00
|
|
|
// *testout << "input, uv = " << gi.u << ", " << gi.v << endl;
|
2022-10-10 19:36:07 +05:00
|
|
|
auto suval = shape_analysis->NextValueOfUV({gi.u, gi.v}, ng2occ(p_), tolerance);
|
|
|
|
gi.trignum = nr+1;
|
|
|
|
suval.Coord(gi.u, gi.v);
|
2022-10-16 16:08:27 +05:00
|
|
|
// *testout << "result, uv = " << gi.u << ", " << gi.v << endl;
|
|
|
|
p_ = occ2ng(surface->Value( gi.u, gi.v ));
|
2022-10-10 19:36:07 +05:00
|
|
|
return true;
|
2022-10-16 16:08:27 +05:00
|
|
|
*/
|
2022-10-10 19:36:07 +05:00
|
|
|
// Old code: do newton iterations manually
|
2021-11-28 20:14:41 +05:00
|
|
|
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);
|
2022-12-13 20:09:28 +05:00
|
|
|
gi.u = u; gi.v = v;
|
2021-11-28 20:14:41 +05:00
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2023-02-13 19:57:53 +05:00
|
|
|
BRepAdaptor_Surface sf(face, Standard_True);
|
|
|
|
BRepLProp_SLProps prop2(sf, 2, 1e-5);
|
|
|
|
prop2.SetParameters (gi.u, gi.v);
|
|
|
|
return max(fabs(prop2.MinCurvature()),
|
|
|
|
fabs(prop2.MaxCurvature()));
|
2021-11-28 20:14:41 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|