mirror of
https://github.com/NGSolve/netgen.git
synced 2024-12-26 22:00:33 +05:00
1501 lines
33 KiB
C++
1501 lines
33 KiB
C++
#include <mystdlib.h>
|
|
|
|
#include <myadt.hpp>
|
|
#include <linalg.hpp>
|
|
#include <gprim.hpp>
|
|
|
|
#include <meshing.hpp>
|
|
|
|
#include "stlgeom.hpp"
|
|
|
|
namespace netgen
|
|
{
|
|
|
|
|
|
//add a point into a pointlist, return pointnumber
|
|
int AddPointIfNotExists(NgArray<Point3d>& ap, const Point3d& p, double eps)
|
|
{
|
|
double eps2 = sqr(eps);
|
|
for (int i = 1; i <= ap.Size(); i++)
|
|
if (Dist2(ap.Get(i),p) <= eps2 )
|
|
return i;
|
|
ap.Append(p);
|
|
return ap.Size();
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
double GetDistFromLine(const Point<3> & lp1, const Point<3> & lp2,
|
|
Point<3> & p)
|
|
{
|
|
Vec3d vn = lp2 - lp1;
|
|
Vec3d v1 = p - lp1;
|
|
Vec3d v2 = lp2 - p;
|
|
|
|
Point3d pold = p;
|
|
|
|
if (v2 * vn <= 0) {p = lp2; return (pold - p).Length();}
|
|
if (v1 * vn <= 0) {p = lp1; return (pold - p).Length();}
|
|
|
|
double vnl = vn.Length();
|
|
if (vnl == 0) {return Dist(lp1,p);}
|
|
|
|
vn /= vnl;
|
|
p = lp1 + (v1 * vn) * vn;
|
|
return (pold - p).Length();
|
|
};
|
|
|
|
double GetDistFromInfiniteLine(const Point<3>& lp1, const Point<3>& lp2, const Point<3>& p)
|
|
{
|
|
Vec3d vn(lp1, lp2);
|
|
Vec3d v1(lp1, p);
|
|
|
|
double vnl = vn.Length();
|
|
|
|
if (vnl == 0)
|
|
{
|
|
return Dist (lp1, p);
|
|
}
|
|
else
|
|
{
|
|
return Cross (vn, v1).Length() / vnl;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//Binary IO-Manipulation
|
|
|
|
|
|
|
|
void FIOReadInt(istream& ios, int& i)
|
|
{
|
|
const int ilen = sizeof(int);
|
|
|
|
char buf[ilen];
|
|
for (int j = 0; j < ilen; j++)
|
|
ios.get(buf[j]);
|
|
memcpy(&i, &buf, ilen);
|
|
}
|
|
|
|
void FIOWriteInt(ostream& ios, const int& i)
|
|
{
|
|
const int ilen = sizeof(int);
|
|
|
|
char buf[ilen];
|
|
memcpy(&buf, &i, ilen);
|
|
|
|
for (int j = 0; j < ilen; j++)
|
|
ios << buf[j];
|
|
}
|
|
|
|
void FIOReadDouble(istream& ios, double& i)
|
|
{
|
|
const int ilen = sizeof(double);
|
|
|
|
char buf[ilen];
|
|
for (int j = 0; j < ilen; j++)
|
|
ios.get(buf[j]);
|
|
|
|
memcpy(&i, &buf, ilen);
|
|
}
|
|
|
|
void FIOWriteDouble(ostream& ios, const double& i)
|
|
{
|
|
const int ilen = sizeof(double);
|
|
|
|
char buf[ilen];
|
|
memcpy(&buf, &i, ilen);
|
|
|
|
for (int j = 0; j < ilen; j++)
|
|
ios << buf[j];
|
|
}
|
|
|
|
void FIOReadFloat(istream& ios, float& i)
|
|
{
|
|
const int ilen = sizeof(float);
|
|
|
|
char buf[ilen];
|
|
int j;
|
|
for (j = 0; j < ilen; j++)
|
|
{
|
|
ios.get(buf[j]);
|
|
}
|
|
memcpy(&i, &buf, ilen);
|
|
}
|
|
|
|
void FIOWriteFloat(ostream& ios, const float& i)
|
|
{
|
|
const int ilen = sizeof(float);
|
|
|
|
char buf[ilen];
|
|
memcpy(&buf, &i, ilen);
|
|
|
|
for (int j = 0; j < ilen; j++)
|
|
ios << buf[j];
|
|
}
|
|
|
|
void FIOReadString(istream& ios, char* str, int len)
|
|
{
|
|
for (int j = 0; j < len; j++)
|
|
ios.get(str[j]);
|
|
}
|
|
|
|
//read string and add terminating 0
|
|
void FIOReadStringE(istream& ios, char* str, int len)
|
|
{
|
|
for (int j = 0; j < len; j++)
|
|
ios.get(str[j]);
|
|
str[len] = 0;
|
|
}
|
|
|
|
void FIOWriteString(ostream& ios, char* str, int len)
|
|
{
|
|
for (int j = 0; j < len; j++)
|
|
ios << str[j];
|
|
}
|
|
|
|
|
|
/*
|
|
void FIOReadInt(istream& ios, int& i)
|
|
{
|
|
const int ilen = sizeof(int);
|
|
|
|
char buf[ilen];
|
|
int j;
|
|
for (j = 0; j < ilen; j++)
|
|
{
|
|
ios.get(buf[ilen-j-1]);
|
|
}
|
|
memcpy(&i, &buf, ilen);
|
|
}
|
|
|
|
void FIOWriteInt(ostream& ios, const int& i)
|
|
{
|
|
const int ilen = sizeof(int);
|
|
|
|
char buf[ilen];
|
|
memcpy(&buf, &i, ilen);
|
|
|
|
int j;
|
|
for (j = 0; j < ilen; j++)
|
|
{
|
|
ios << buf[ilen-j-1];
|
|
}
|
|
}
|
|
|
|
void FIOReadDouble(istream& ios, double& i)
|
|
{
|
|
const int ilen = sizeof(double);
|
|
|
|
char buf[ilen];
|
|
int j;
|
|
for (j = 0; j < ilen; j++)
|
|
{
|
|
ios.get(buf[ilen-j-1]);
|
|
}
|
|
memcpy(&i, &buf, ilen);
|
|
}
|
|
|
|
void FIOWriteDouble(ostream& ios, const double& i)
|
|
{
|
|
const int ilen = sizeof(double);
|
|
|
|
char buf[ilen];
|
|
memcpy(&buf, &i, ilen);
|
|
|
|
int j;
|
|
for (j = 0; j < ilen; j++)
|
|
{
|
|
ios << buf[ilen-j-1];
|
|
}
|
|
}
|
|
|
|
void FIOReadFloat(istream& ios, float& i)
|
|
{
|
|
const int ilen = sizeof(float);
|
|
|
|
char buf[ilen];
|
|
int j;
|
|
for (j = 0; j < ilen; j++)
|
|
{
|
|
ios.get(buf[ilen-j-1]);
|
|
}
|
|
memcpy(&i, &buf, ilen);
|
|
}
|
|
|
|
void FIOWriteFloat(ostream& ios, const float& i)
|
|
{
|
|
const int ilen = sizeof(float);
|
|
|
|
char buf[ilen];
|
|
memcpy(&buf, &i, ilen);
|
|
|
|
int j;
|
|
for (j = 0; j < ilen; j++)
|
|
{
|
|
ios << buf[ilen-j-1];
|
|
}
|
|
}
|
|
|
|
void FIOReadString(istream& ios, char* str, int len)
|
|
{
|
|
int j;
|
|
for (j = 0; j < len; j++)
|
|
{
|
|
ios.get(str[j]);
|
|
}
|
|
}
|
|
|
|
//read string and add terminating 0
|
|
void FIOReadStringE(istream& ios, char* str, int len)
|
|
{
|
|
int j;
|
|
for (j = 0; j < len; j++)
|
|
{
|
|
ios.get(str[j]);
|
|
}
|
|
str[len] = 0;
|
|
}
|
|
|
|
void FIOWriteString(ostream& ios, char* str, int len)
|
|
{
|
|
int j;
|
|
for (j = 0; j < len; j++)
|
|
{
|
|
ios << str[j];
|
|
}
|
|
}
|
|
*/
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
STLReadTriangle :: STLReadTriangle (const Point<3> * apts,
|
|
const Vec<3> & anormal)
|
|
{
|
|
pts[0] = apts[0];
|
|
pts[1] = apts[1];
|
|
pts[2] = apts[2];
|
|
normal = anormal;
|
|
}
|
|
|
|
|
|
|
|
STLTriangle :: STLTriangle(const STLPointId * apts)
|
|
{
|
|
pts[0] = apts[0];
|
|
pts[1] = apts[1];
|
|
pts[2] = apts[2];
|
|
|
|
facenum = 0;
|
|
}
|
|
|
|
int STLTriangle :: IsNeighbourFrom(const STLTriangle& t) const
|
|
{
|
|
//triangles must have same orientation!!!
|
|
|
|
for(int i = 0; i <= 2; i++)
|
|
for(int j = 0; j <= 2; j++)
|
|
if (t.pts[(i+1)%3] == pts[j] &&
|
|
t.pts[i] == pts[(j+1)%3])
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int STLTriangle :: IsWrongNeighbourFrom(const STLTriangle& t) const
|
|
{
|
|
//triangles have not same orientation!!!
|
|
for(int i = 0; i <= 2; i++)
|
|
for(int j = 0; j <= 2; j++)
|
|
if (t.pts[(i+1)%3] == pts[(j+1)%3] &&
|
|
t.pts[i] == pts[j])
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void STLTriangle :: GetNeighbourPoints(const STLTriangle& t, STLPointId & p1, STLPointId & p2) const
|
|
{
|
|
for(int i = 1; i <= 3; i++)
|
|
for(int j = 1; j <= 3; j++)
|
|
if (t.PNumMod(i+1) == PNumMod(j) &&
|
|
t.PNumMod(i) == PNumMod(j+1))
|
|
{
|
|
p1 = PNumMod(j);
|
|
p2 = PNumMod(j+1);
|
|
return;
|
|
}
|
|
|
|
PrintSysError("Get neighbourpoints failed!");
|
|
}
|
|
|
|
int STLTriangle :: GetNeighbourPointsAndOpposite(const STLTriangle& t, STLPointId & p1,
|
|
STLPointId & p2, STLPointId & po) const
|
|
{
|
|
for(int i = 1; i <= 3; i++)
|
|
for(int j = 1; j <= 3; j++)
|
|
if (t.PNumMod(i+1) == PNumMod(j) &&
|
|
t.PNumMod(i) == PNumMod(j+1))
|
|
{
|
|
p1 = PNumMod(j);
|
|
p2 = PNumMod(j+1);
|
|
po = PNumMod(j+2);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Vec<3> STLTriangle :: GeomNormal(const Array<Point<3>,STLPointId>& ap) const
|
|
{
|
|
const Point<3> & p1 = ap[PNum(1)];
|
|
const Point<3> & p2 = ap[PNum(2)];
|
|
const Point<3> & p3 = ap[PNum(3)];
|
|
|
|
return Cross(p2-p1, p3-p1);
|
|
}
|
|
|
|
|
|
void STLTriangle :: SetNormal (const Vec<3> & n)
|
|
{
|
|
double len = n.Length();
|
|
if (len > 0)
|
|
{
|
|
normal = n;
|
|
normal.Normalize();
|
|
}
|
|
else
|
|
{
|
|
normal = Vec<3> (1, 0, 0);
|
|
}
|
|
}
|
|
|
|
|
|
void STLTriangle :: ChangeOrientation()
|
|
{
|
|
normal *= -1;
|
|
Swap(pts[0],pts[1]);
|
|
}
|
|
|
|
|
|
|
|
double STLTriangle :: Area(const Array<Point<3>,STLPointId>& ap) const
|
|
{
|
|
return 0.5 * Cross(ap[PNum(2)]-ap[PNum(1)],
|
|
ap[PNum(3)]-ap[PNum(1)]).Length();
|
|
}
|
|
|
|
double STLTriangle :: MinHeight(const Array<Point<3>,STLPointId>& ap) const
|
|
{
|
|
double ml = MaxLength(ap);
|
|
if (ml != 0) {return 2.*Area(ap)/ml;}
|
|
PrintWarning("max Side Length of a triangle = 0!!!");
|
|
return 0;
|
|
}
|
|
|
|
double STLTriangle :: MaxLength(const Array<Point<3>,STLPointId>& ap) const
|
|
{
|
|
return max3(Dist(ap[PNum(1)],ap[PNum(2)]),
|
|
Dist(ap[PNum(2)],ap[PNum(3)]),
|
|
Dist(ap[PNum(3)],ap[PNum(1)]));
|
|
}
|
|
|
|
void STLTriangle :: ProjectInPlain(const Array<Point<3>,STLPointId>& ap,
|
|
const Vec<3> & n, Point<3> & pp) const
|
|
{
|
|
const Point<3> & p1 = ap[PNum(1)];
|
|
const Point<3> & p2 = ap[PNum(2)];
|
|
const Point<3> & p3 = ap[PNum(3)];
|
|
|
|
Vec<3> v1 = p2 - p1;
|
|
Vec<3> v2 = p3 - p1;
|
|
Vec<3> nt = Cross(v1, v2);
|
|
|
|
double c = - (p1(0)*nt(0) + p1(1)*nt(1) + p1(2)*nt(2));
|
|
|
|
double prod = n * nt;
|
|
|
|
if (fabs(prod) == 0)
|
|
{
|
|
pp = Point<3>(1.E20,1.E20,1.E20);
|
|
return;
|
|
}
|
|
|
|
double nfact = -(pp(0)*nt(0) + pp(1)*nt(1) + pp(2)*nt(2) + c) / (prod);
|
|
pp = pp + (nfact) * n;
|
|
|
|
}
|
|
|
|
|
|
int STLTriangle :: ProjectInPlain (const Array<Point<3>,STLPointId>& ap,
|
|
const Vec<3> & nproj,
|
|
Point<3> & pp, Vec<3> & lam) const
|
|
{
|
|
const Point<3> & p1 = ap[PNum(1)];
|
|
const Point<3> & p2 = ap[PNum(2)];
|
|
const Point<3> & p3 = ap[PNum(3)];
|
|
|
|
Vec<3> v1 = p2-p1;
|
|
Vec<3> v2 = p3-p1;
|
|
|
|
Mat<3> mat;
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
mat(i,0) = v1(i);
|
|
mat(i,1) = v2(i);
|
|
mat(i,2) = nproj(i);
|
|
}
|
|
|
|
int err = 0;
|
|
mat.Solve (pp-p1, lam);
|
|
// int err = SolveLinearSystem (v1, v2, nproj, pp-p1, lam);
|
|
|
|
if (!err)
|
|
{
|
|
// pp = p1 + lam(0) * v1 + lam(1) * v2;
|
|
|
|
pp(0) = p1(0) + lam(0) * v1(0) + lam(1) * v2(0);
|
|
pp(1) = p1(1) + lam(0) * v1(1) + lam(1) * v2(1);
|
|
pp(2) = p1(2) + lam(0) * v1(2) + lam(1) * v2(2);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void STLTriangle :: ProjectInPlain(const Array<Point<3>,STLPointId>& ap,
|
|
Point<3> & pp) const
|
|
{
|
|
const Point<3> & p1 = ap[PNum(1)];
|
|
const Point<3> & p2 = ap[PNum(2)];
|
|
const Point<3> & p3 = ap[PNum(3)];
|
|
|
|
Vec<3> v1 = p2 - p1;
|
|
Vec<3> v2 = p3 - p1;
|
|
Vec<3> nt = Cross(v1, v2);
|
|
|
|
double c = - (p1(0)*nt(0) + p1(1)*nt(1) + p1(2)*nt(2));
|
|
|
|
double prod = nt * nt;
|
|
|
|
double nfact = -(pp(0)*nt(0) + pp(1)*nt(1) + pp(2)*nt(2) + c) / (prod);
|
|
|
|
pp = pp + (nfact) * nt;
|
|
}
|
|
|
|
bool STLTriangle :: PointInside(const Array<Point<3>,STLPointId> & ap,
|
|
const Point<3> & pp) const
|
|
{
|
|
const Point<3> & p1 = ap[PNum(1)];
|
|
const Point<3> & p2 = ap[PNum(2)];
|
|
const Point<3> & p3 = ap[PNum(3)];
|
|
|
|
Vec<3> v1 = p2 - p1;
|
|
Vec<3> v2 = p3 - p1;
|
|
Vec<3> v = pp - p1;
|
|
double det, l1, l2;
|
|
Vec<3> ex, ey, ez;
|
|
|
|
|
|
ez = GeomNormal(ap);
|
|
ez /= ez.Length();
|
|
ex = v1;
|
|
ex /= ex.Length();
|
|
ey = Cross (ez, ex);
|
|
|
|
Vec<2> v1p(v1*ex, v1*ey);
|
|
Vec<2> v2p(v2*ex, v2*ey);
|
|
Vec<2> vp(v*ex, v*ey);
|
|
|
|
det = v2p(1) * v1p(0) - v2p(0) * v1p(1);
|
|
|
|
if (fabs(det) == 0) {return 0;}
|
|
|
|
l2 = (vp(1) * v1p(0) - vp(0) * v1p(1)) / det;
|
|
|
|
if (v1p(0) != 0.)
|
|
{
|
|
l1 = (vp(0) - l2 * v2p(0)) / v1p(0);
|
|
}
|
|
else if (v1p(1) != 0.)
|
|
{
|
|
l1 = (vp(1) - l2 * v2p(1)) / v1p(1);
|
|
}
|
|
else {return 0;}
|
|
|
|
if (l1 >= -1E-10 && l2 >= -1E-10 && l1 + l2 <= 1.+1E-10) {return 1;}
|
|
return 0;
|
|
}
|
|
|
|
double STLTriangle :: GetNearestPoint(const Array<Point<3>,STLPointId>& ap,
|
|
Point<3> & p3d) const
|
|
{
|
|
Point<3> p = p3d;
|
|
ProjectInPlain(ap, p);
|
|
double dist = (p - p3d).Length();
|
|
|
|
if (PointInside(ap, p)) {p3d = p; return dist;}
|
|
else
|
|
{
|
|
Point<3> pf = 0.0;
|
|
double nearest = 1E50;
|
|
//int fi = 0;
|
|
for (int j = 1; j <= 3; j++)
|
|
{
|
|
p = p3d;
|
|
dist = GetDistFromLine(ap[PNum(j)], ap[PNumMod(j+1)], p);
|
|
if (dist < nearest)
|
|
{
|
|
nearest = dist;
|
|
pf = p;
|
|
}
|
|
}
|
|
p3d = pf;
|
|
return nearest;
|
|
}
|
|
}
|
|
|
|
bool STLTriangle :: HasEdge(STLPointId p1, STLPointId p2) const
|
|
{
|
|
for (int i = 1; i <= 3; i++)
|
|
if (p1 == PNum(i) && p2 == PNumMod(i+1))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
ostream& operator<<(ostream& os, const STLTriangle& t)
|
|
{
|
|
os << "[";
|
|
os << t[0] << ",";
|
|
os << t[1] << ",";
|
|
os << t[2] << "]";
|
|
|
|
return os;
|
|
};
|
|
|
|
|
|
|
|
STLTopEdge :: STLTopEdge ()
|
|
{
|
|
pts[0] = pts[1] = 0;
|
|
trigs[0] = trigs[1] = 0;
|
|
cosangle = 1;
|
|
status = ED_UNDEFINED;
|
|
}
|
|
|
|
STLTopEdge :: STLTopEdge (STLPointId p1, STLPointId p2, int trig1, int trig2)
|
|
{
|
|
pts[0] = p1;
|
|
pts[1] = p2;
|
|
trigs[0] = trig1;
|
|
trigs[1] = trig2;
|
|
cosangle = 1;
|
|
status = ED_UNDEFINED;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//+++++++++++++++++++ STL CHART +++++++++++++++++++++++++++++++
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
STLChart :: STLChart(STLGeometry * ageometry, const STLParameters& astlparam)
|
|
: geometry(ageometry), stlparam(astlparam)
|
|
{
|
|
// charttrigs = new NgArray<int> (0,0);
|
|
// outertrigs = new NgArray<int> (0,0);
|
|
// ilimit = new NgArray<twoint> (0,0);
|
|
// olimit = new NgArray<twoint> (0,0);
|
|
|
|
geometry = ageometry;
|
|
|
|
if ( stlparam.usesearchtree == 1)
|
|
{
|
|
Box<3> box = geometry->GetBoundingBox();
|
|
box.Increase (0.2*box.Diam()+1e-12);
|
|
searchtree = new BoxTree<3,STLTrigId> (box);
|
|
/*
|
|
searchtree = new BoxTree<3> (geometry->GetBoundingBox().PMin() - Vec3d(1,1,1),
|
|
geometry->GetBoundingBox().PMax() + Vec3d(1,1,1));
|
|
*/
|
|
}
|
|
else
|
|
searchtree = NULL;
|
|
}
|
|
|
|
STLChart :: ~STLChart()
|
|
{
|
|
delete searchtree;
|
|
}
|
|
|
|
void STLChart :: AddChartTrig(STLTrigId i)
|
|
{
|
|
// static int timer = NgProfiler::CreateTimer ("STLChart::AddChartTrig");
|
|
// NgProfiler::RegionTimer reg(timer);
|
|
|
|
charttrigs.Append(i);
|
|
|
|
const STLTriangle & trig = geometry->GetTriangle(i);
|
|
const Point<3> & p1 = geometry->GetPoint (trig.PNum(1));
|
|
const Point<3> & p2 = geometry->GetPoint (trig.PNum(2));
|
|
const Point<3> & p3 = geometry->GetPoint (trig.PNum(3));
|
|
|
|
/*
|
|
Point3d pmin(p1), pmax(p1);
|
|
pmin.SetToMin (p2);
|
|
pmin.SetToMin (p3);
|
|
pmax.SetToMax (p2);
|
|
pmax.SetToMax (p3);
|
|
*/
|
|
/*
|
|
Box<3> box(p1);
|
|
box.Add(p2);
|
|
box.Add(p3);
|
|
*/
|
|
Box<3> box(p1,p2,p3);
|
|
if (!geomsearchtreeon && (stlparam.usesearchtree == 1))
|
|
// {searchtree->Insert (pmin, pmax, i);}
|
|
{
|
|
searchtree->Insert (box, i);
|
|
}
|
|
}
|
|
|
|
void STLChart :: AddOuterTrig(STLTrigId i)
|
|
{
|
|
// static int timer = NgProfiler::CreateTimer ("STLChart::AddOuterTrig");
|
|
// NgProfiler::RegionTimer reg(timer);
|
|
|
|
outertrigs.Append(i);
|
|
|
|
const STLTriangle & trig = geometry->GetTriangle(i);
|
|
const Point3d & p1 = geometry->GetPoint (trig.PNum(1));
|
|
const Point3d & p2 = geometry->GetPoint (trig.PNum(2));
|
|
const Point3d & p3 = geometry->GetPoint (trig.PNum(3));
|
|
|
|
Point3d pmin(p1), pmax(p1);
|
|
pmin.SetToMin (p2);
|
|
pmin.SetToMin (p3);
|
|
pmax.SetToMax (p2);
|
|
pmax.SetToMax (p3);
|
|
|
|
if (!geomsearchtreeon && (stlparam.usesearchtree==1))
|
|
{searchtree->Insert (pmin, pmax, i);}
|
|
}
|
|
|
|
bool STLChart :: IsInWholeChart(int nr) const
|
|
{
|
|
return charttrigs.Contains(nr) || outertrigs.Contains(nr);
|
|
}
|
|
|
|
void STLChart :: GetTrianglesInBox (const Point3d & pmin,
|
|
const Point3d & pmax,
|
|
NgArray<STLTrigId> & trias) const
|
|
{
|
|
if (geomsearchtreeon) {PrintMessage(5,"geomsearchtreeon is set!!!");}
|
|
|
|
if (searchtree)
|
|
searchtree -> GetIntersecting (pmin, pmax, trias);
|
|
else
|
|
{
|
|
Box<3> box1(pmin, pmax);
|
|
box1.Increase (1e-2*box1.Diam());
|
|
|
|
trias.SetSize(0);
|
|
|
|
int nt = GetNT();
|
|
for (int i = 1; i <= nt; i++)
|
|
{
|
|
STLTrigId trignum = GetTrig1(i);
|
|
const STLTriangle & trig = geometry->GetTriangle(trignum);
|
|
Box<3> box2(geometry->GetPoint (trig.PNum(1)),
|
|
geometry->GetPoint (trig.PNum(2)),
|
|
geometry->GetPoint (trig.PNum(3)));
|
|
|
|
if (box1.Intersect (box2))
|
|
trias.Append (trignum);
|
|
}
|
|
}
|
|
}
|
|
|
|
//trigs may contain the same triangle double
|
|
void STLChart :: MoveToOuterChart(const NgArray<int>& trigs)
|
|
{
|
|
if (!trigs.Size()) return;
|
|
for (int i = 1; i <= trigs.Size(); i++)
|
|
{
|
|
if (charttrigs[trigs.Get(i)-1] != -1)
|
|
AddOuterTrig(charttrigs[trigs.Get(i)-1]);
|
|
charttrigs[trigs.Get(i)-1] = -1;
|
|
}
|
|
DelChartTrigs(trigs);
|
|
}
|
|
|
|
//trigs may contain the same triangle double
|
|
void STLChart :: DelChartTrigs(const NgArray<int>& trigs)
|
|
{
|
|
if (!trigs.Size()) return;
|
|
|
|
for (int i = 1; i <= trigs.Size(); i++)
|
|
charttrigs[trigs.Get(i)-1] = -1;
|
|
|
|
int cnt = 0;
|
|
for (int i = 1; i <= charttrigs.Size(); i++)
|
|
{
|
|
if (charttrigs[i-1] == -1)
|
|
cnt++;
|
|
if (cnt != 0 && i < charttrigs.Size())
|
|
charttrigs[i-cnt] = charttrigs[i];
|
|
}
|
|
|
|
int i = charttrigs.Size() - trigs.Size();
|
|
charttrigs.SetSize(i);
|
|
|
|
if (!geomsearchtreeon && stlparam.usesearchtree == 1)
|
|
{
|
|
PrintMessage(7, "Warning: unsecure routine due to first use of searchtrees!!!");
|
|
//bould new searchtree!!!
|
|
searchtree = new BoxTree<3,STLTrigId> (geometry->GetBoundingBox().PMin() - Vec3d(1,1,1),
|
|
geometry->GetBoundingBox().PMax() + Vec3d(1,1,1));
|
|
|
|
for (int i = 1; i <= charttrigs.Size(); i++)
|
|
{
|
|
const STLTriangle & trig = geometry->GetTriangle(i);
|
|
const Point3d & p1 = geometry->GetPoint (trig.PNum(1));
|
|
const Point3d & p2 = geometry->GetPoint (trig.PNum(2));
|
|
const Point3d & p3 = geometry->GetPoint (trig.PNum(3));
|
|
|
|
Point3d pmin(p1), pmax(p1);
|
|
pmin.SetToMin (p2);
|
|
pmin.SetToMin (p3);
|
|
pmax.SetToMax (p2);
|
|
pmax.SetToMax (p3);
|
|
|
|
searchtree->Insert (pmin, pmax, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void STLChart :: SetNormal (const Point<3> & apref, const Vec<3> & anormal)
|
|
{
|
|
pref = apref;
|
|
normal = anormal;
|
|
double len = normal.Length();
|
|
if (len) normal /= len;
|
|
else normal = Vec<3> (1, 0, 0);
|
|
|
|
t1 = normal.GetNormal ();
|
|
t2 = Cross (normal, t1);
|
|
}
|
|
|
|
void STLChart :: BuildInnerSearchTree()
|
|
{
|
|
Box<2> chart_bbox(Box<2>::EMPTY_BOX);
|
|
for (STLTrigId trigid : charttrigs)
|
|
{
|
|
for (STLPointId pi : (*geometry)[trigid].PNums())
|
|
{
|
|
Point<3> p = (*geometry)[pi];
|
|
Point<2> p2d = Project2d(p);
|
|
chart_bbox.Add(p2d);
|
|
}
|
|
}
|
|
chart_bbox.Increase (1e-2*chart_bbox.Diam());
|
|
inner_searchtree = make_unique<BoxTree<2,STLTrigId>> (chart_bbox);
|
|
for (STLTrigId trigid : charttrigs)
|
|
{
|
|
Box<2> bbox(Box<2>::EMPTY_BOX);
|
|
for (STLPointId pi : (*geometry)[trigid].PNums())
|
|
{
|
|
Point<3> p = (*geometry)[pi];
|
|
Point<2> p2d = Project2d(p);
|
|
bbox.Add(p2d);
|
|
}
|
|
inner_searchtree->Insert (bbox, trigid);
|
|
}
|
|
}
|
|
|
|
STLTrigId STLChart :: ProjectNormal (Point<3> & p3d) const
|
|
{
|
|
|
|
int nt = GetNT();
|
|
double lamtol = 1e-6;
|
|
QuadraticFunction3d quadfun(p3d, GetNormal());
|
|
|
|
int starttrig = 1;
|
|
if (inner_searchtree)
|
|
{
|
|
starttrig = GetNChartT()+1;
|
|
Point<2> p2d = Project2d (p3d);
|
|
|
|
|
|
bool inside = false;
|
|
STLTrigId trignum;
|
|
inner_searchtree->GetFirstIntersecting(p2d, p2d, [&](auto i)
|
|
{
|
|
auto & trig = geometry->GetTriangle(i);
|
|
const Point<3> & c = trig.center;
|
|
|
|
if (quadfun.Eval(c) > sqr (trig.rad))
|
|
return false;
|
|
|
|
Point<3> p = p3d;
|
|
Vec<3> lam;
|
|
int err = trig.ProjectInPlain(geometry->GetPoints(), GetNormal(), p, lam);
|
|
inside = (err == 0 && lam(0) > -lamtol &&
|
|
lam(1) > -lamtol && (1-lam(0)-lam(1)) > -lamtol);
|
|
|
|
if (inside)
|
|
{
|
|
trignum=i;
|
|
p3d = p;
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
if(inside)
|
|
return trignum;
|
|
}
|
|
|
|
|
|
for (int j = starttrig; j <= nt; j++)
|
|
{
|
|
STLTrigId i = GetTrig1(j);
|
|
auto & trig = geometry->GetTriangle(i);
|
|
const Point<3> & c = trig.center;
|
|
|
|
if (quadfun.Eval(c) > sqr (trig.rad))
|
|
continue;
|
|
|
|
Point<3> p = p3d;
|
|
Vec<3> lam;
|
|
int err = trig.ProjectInPlain(geometry->GetPoints(), GetNormal(), p, lam);
|
|
bool inside = (err == 0 && lam(0) > -lamtol &&
|
|
lam(1) > -lamtol && (1-lam(0)-lam(1)) > -lamtol);
|
|
|
|
if (inside)
|
|
{
|
|
p3d = p;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Point<2> STLChart :: Project2d (const Point<3> & p3d) const
|
|
{
|
|
Vec<3> v = p3d-pref;
|
|
return Point<2> (t1 * v, t2 * v);
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
Point3d p1, p2, center;
|
|
double rad;
|
|
int i1, i2;
|
|
public:
|
|
*/
|
|
|
|
/*
|
|
STLBoundarySeg ::
|
|
STLBoundarySeg (int ai1, int ai2, const NgArray<Point<3> > & points,
|
|
const STLChart * chart)
|
|
{
|
|
i1 = ai1;
|
|
i2 = ai2;
|
|
p1 = points.Get(i1);
|
|
p2 = points.Get(i2);
|
|
center = ::netgen::Center (p1, p2);
|
|
rad = Dist (p1, center);
|
|
|
|
p2d1 = chart->Project2d (p1);
|
|
p2d2 = chart->Project2d (p2);
|
|
|
|
boundingbox.Set (p2d1);
|
|
boundingbox.Add (p2d2);
|
|
}
|
|
*/
|
|
|
|
void STLBoundarySeg :: Swap ()
|
|
{
|
|
::netgen::Swap (i1, i2);
|
|
::netgen::Swap (p1, p2);
|
|
}
|
|
|
|
|
|
|
|
STLBoundary :: STLBoundary (STLGeometry * ageometry)
|
|
: geometry(ageometry)
|
|
{ ; }
|
|
|
|
|
|
/*
|
|
void STLBoundary :: AddOrDelSegment(const STLBoundarySeg & seg)
|
|
{
|
|
bool found = false;
|
|
for (int i = 1; i <= boundary.Size(); i++)
|
|
{
|
|
if (found) { boundary.Elem(i-1) = boundary.Get(i); }
|
|
if (boundary.Get(i) == seg) { found = true; }
|
|
}
|
|
if (!found)
|
|
{
|
|
boundary.Append(seg);
|
|
}
|
|
else
|
|
{
|
|
boundary.SetSize(boundary.Size()-1);
|
|
}
|
|
}
|
|
*/
|
|
|
|
void STLBoundary ::AddTriangle(const STLTriangle & t)
|
|
{
|
|
// static Timer timer("STLBoundary::AddTriangle"); RegionTimer reg(timer);
|
|
// static int timer_old = NgProfiler::CreateTimer ("STLChart::AddTriangle_old");
|
|
// static int timer_new = NgProfiler::CreateTimer ("STLChart::AddTriangle_new");
|
|
|
|
// NgProfiler::StartTimer (timer_old);
|
|
|
|
#ifdef ADDTRIGOLD
|
|
int i;
|
|
int found1 = 0;
|
|
int found2 = 0;
|
|
int found3 = 0;
|
|
//int offset = 0;
|
|
|
|
|
|
STLBoundarySeg seg1(t[0],t[1], geometry->GetPoints(), chart);
|
|
STLBoundarySeg seg2(t[1],t[2], geometry->GetPoints(), chart);
|
|
STLBoundarySeg seg3(t[2],t[0], geometry->GetPoints(), chart);
|
|
|
|
seg1.SetSmoothEdge (geometry->IsSmoothEdge (seg1.I1(), seg1.I2()));
|
|
seg2.SetSmoothEdge (geometry->IsSmoothEdge (seg2.I1(), seg2.I2()));
|
|
seg3.SetSmoothEdge (geometry->IsSmoothEdge (seg3.I1(), seg3.I2()));
|
|
|
|
/*
|
|
for (i = 1; i <= boundary.Size(); i++)
|
|
{
|
|
if (offset) {boundary.Elem(i-offset) = boundary.Get(i);}
|
|
if (boundary.Get(i) == seg1) {found1 = 1; offset++;}
|
|
if (boundary.Get(i) == seg2) {found2 = 1; offset++;}
|
|
if (boundary.Get(i) == seg3) {found3 = 1; offset++;}
|
|
}
|
|
|
|
if (offset)
|
|
{
|
|
boundary.SetSize(boundary.Size()-offset);
|
|
}
|
|
*/
|
|
for (i = boundary.Size(); i >= 1; i--)
|
|
{
|
|
if (boundary.Get(i) == seg1)
|
|
{ boundary.DeleteElement (i); found1 = 1; }
|
|
else if (boundary.Get(i) == seg2)
|
|
{ boundary.DeleteElement (i); found2 = 1; }
|
|
else if (boundary.Get(i) == seg3)
|
|
{ boundary.DeleteElement (i); found3 = 1; }
|
|
}
|
|
|
|
if (!found1)
|
|
{
|
|
seg1.Swap();
|
|
boundary.Append(seg1);
|
|
/*
|
|
int newnr;
|
|
if (freelist.Size())
|
|
{
|
|
newnr = freelist.Last();
|
|
freelist.DeleteLast();
|
|
boundary[newnr] = seg1;
|
|
}
|
|
else
|
|
{
|
|
boundary.Append(seg1);
|
|
newnr = boundary.Size();
|
|
}
|
|
// cout << "tree add el " << boundary.Size() << endl;
|
|
if (searchtree)
|
|
{
|
|
// cout << "add " << boundary.Size() << endl;
|
|
searchtree->Insert (seg1.BoundingBox(), newnr);
|
|
}
|
|
*/
|
|
}
|
|
|
|
if (!found2)
|
|
{
|
|
seg2.Swap();
|
|
boundary.Append(seg2);
|
|
/*
|
|
int newnr;
|
|
if (freelist.Size())
|
|
{
|
|
newnr = freelist.Last();
|
|
freelist.DeleteLast();
|
|
boundary[newnr] = seg2;
|
|
}
|
|
else
|
|
{
|
|
boundary.Append(seg2);
|
|
newnr = boundary.Size();
|
|
}
|
|
|
|
// boundary.Append(seg2);
|
|
// cout << "tree add el " << boundary.Size() << endl;
|
|
if (searchtree)
|
|
{
|
|
// cout << "add " << boundary.Size() << endl;
|
|
searchtree->Insert (seg2.BoundingBox(), newnr);
|
|
}
|
|
*/
|
|
}
|
|
if (!found3)
|
|
{
|
|
seg3.Swap();
|
|
boundary.Append(seg3);
|
|
/*
|
|
int newnr;
|
|
if (freelist.Size())
|
|
{
|
|
newnr = freelist.Last();
|
|
freelist.DeleteLast();
|
|
boundary[newnr] = seg3;
|
|
}
|
|
else
|
|
{
|
|
boundary.Append(seg3);
|
|
newnr = boundary.Size();
|
|
}
|
|
|
|
// cout << "tree add el " << boundary.Size() << endl;
|
|
if (searchtree)
|
|
{
|
|
// cout << "add " << boundary.Size() << endl;
|
|
searchtree->Insert (seg3.BoundingBox(), newnr);
|
|
}
|
|
*/
|
|
}
|
|
#endif
|
|
|
|
// NgProfiler::StopTimer (timer_old);
|
|
|
|
// NgProfiler::StartTimer (timer_new);
|
|
|
|
INDEX_2 segs[3];
|
|
segs[0] = INDEX_2(t[0], t[1]);
|
|
segs[1] = INDEX_2(t[1], t[2]);
|
|
segs[2] = INDEX_2(t[2], t[0]);
|
|
|
|
if(!searchtree)
|
|
BuildSearchTree();
|
|
|
|
for (auto seg : segs)
|
|
{
|
|
STLBoundarySeg bseg(seg[0], seg[1], geometry->GetPoints(), chart);
|
|
bseg.SetSmoothEdge (geometry->IsSmoothEdge (seg[0],seg[1]));
|
|
|
|
INDEX_2 op(seg[1], seg[0]);
|
|
if (boundary_ht.Used(op))
|
|
{
|
|
boundary_ht.Delete(op);
|
|
if (searchtree)
|
|
searchtree->DeleteElement(op);
|
|
}
|
|
else
|
|
{
|
|
boundary_ht[seg] = bseg;
|
|
if (searchtree)
|
|
searchtree->Insert (bseg.BoundingBox(), seg);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool STLBoundary :: TestSeg(const Point<3>& p1, const Point<3> & p2, const Vec<3> & sn,
|
|
double sinchartangle, int divisions, Array<Point<3>,STLPointId>& points, double eps)
|
|
{
|
|
if (usechartnormal)
|
|
return TestSegChartNV (p1, p2, sn);
|
|
|
|
#ifdef NONE
|
|
// for statistics
|
|
{
|
|
int i;
|
|
static NgArray<int> cntclass;
|
|
static int cnt = 0;
|
|
static int cnti = 0, cnto = 0;
|
|
static long int cntsegs = 0;
|
|
if (cntclass.Size() == 0)
|
|
{
|
|
cntclass.SetSize (20);
|
|
for (i = 1; i <= cntclass.Size(); i++)
|
|
cntclass.Elem(i) = 0;
|
|
}
|
|
|
|
cntsegs += NOSegments();
|
|
int cla = int (log (double(NOSegments()+1)) / log(2.0));
|
|
if (cla < 1) cla = 1;
|
|
if (cla > cntclass.Size()) cla = cntclass.Size();
|
|
cntclass.Elem(cla)++;
|
|
cnt++;
|
|
if (divisions)
|
|
cnti++;
|
|
else
|
|
cnto++;
|
|
if (cnt > 100000)
|
|
{
|
|
cnt = 0;
|
|
/*
|
|
(*testout) << "TestSeg-calls for classes:" << endl;
|
|
(*testout) << cnti << " inner calls, " << cnto << " outercalls" << endl;
|
|
(*testout) << "total testes segments: " << cntsegs << endl;
|
|
for (i = 1; i <= cntclass.Size(); i++)
|
|
{
|
|
(*testout) << int (exp (i * log(2.0))) << " bnd segs: " << cntclass.Get(i) << endl;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int i,j,k;
|
|
Point<3> seg1p/*, seg2p*/;
|
|
Point<3> sp1,sp2;
|
|
double lambda1, lambda2, vlen2;
|
|
Vec<3> vptpl;
|
|
double sinchartangle2 = sqr(sinchartangle);
|
|
double scal;
|
|
int possible;
|
|
|
|
//double maxval = -1;
|
|
//double maxvalnew = -1;
|
|
|
|
|
|
|
|
double scalp1 = p1(0) * sn(0) + p1(1) * sn(1) + p1(2) * sn(2);
|
|
double scalp2 = p2(0) * sn(0) + p2(1) * sn(1) + p2(2) * sn(2);
|
|
double minl = min2(scalp1, scalp2);
|
|
double maxl = max2(scalp1, scalp2);
|
|
Point<3> c = Center (p1, p2);
|
|
double dist1 = Dist (c, p1);
|
|
|
|
/*
|
|
int nseg = NOSegments();
|
|
for (j = 1; j <= nseg; j++)
|
|
{
|
|
const STLBoundarySeg & seg = GetSegment(j);
|
|
*/
|
|
for(auto [i2, seg] : boundary_ht)
|
|
{
|
|
|
|
if (seg.IsSmoothEdge())
|
|
continue;
|
|
|
|
|
|
sp1 = seg.P1();
|
|
sp2 = seg.P2();
|
|
|
|
// Test, ob Spiral Konfikt moeglich
|
|
|
|
possible = 1;
|
|
|
|
double scalsp1 = sp1(0) * sn(0) + sp1(1) * sn(1) + sp1(2) * sn(2);
|
|
double scalsp2 = sp2(0) * sn(0) + sp2(1) * sn(1) + sp2(2) * sn(2);
|
|
|
|
double minsl = min2(scalsp1, scalsp2);
|
|
double maxsl = max2(scalsp1, scalsp2);
|
|
|
|
double maxdiff = max2 (maxsl - minl, maxl - minsl);
|
|
|
|
/*
|
|
Point3d sc = Center (sp1, sp2);
|
|
double mindist = Dist(c, sc) - dist1 - GetSegment(j).Radius();
|
|
if (maxdiff < sinchartangle * mindist)
|
|
{
|
|
possible = 0;
|
|
}
|
|
*/
|
|
|
|
double hscal = maxdiff + sinchartangle * (dist1 + seg.Radius());
|
|
if (hscal * hscal < sinchartangle * Dist2(c, seg.center ))
|
|
possible = 0;
|
|
|
|
|
|
/*
|
|
if (possible)
|
|
{
|
|
double mindist2ex = MinDistLL2 (p1, p2, sp1, sp2);
|
|
if (maxdiff * maxdiff < sinchartangle2 * mindist2ex)
|
|
possible = 0;
|
|
}
|
|
*/
|
|
|
|
if (possible)
|
|
{
|
|
LinearPolynomial2V lp (scalp1 - scalsp1,
|
|
scalp2 - scalp1,
|
|
-(scalsp2 - scalsp1));
|
|
QuadraticPolynomial2V slp;
|
|
slp.Square (lp);
|
|
|
|
|
|
Vec3d v (p1, sp1);
|
|
Vec3d vl (p1, p2);
|
|
Vec3d vsl (sp1, sp2);
|
|
|
|
QuadraticPolynomial2V qp (v.Length2(),
|
|
-2 * (v * vl),
|
|
2 * (v * vsl),
|
|
vl.Length2(),
|
|
-2 * (vl * vsl),
|
|
vsl.Length2());
|
|
|
|
slp.Add (-sinchartangle2, qp);
|
|
|
|
double hv = slp.MaxUnitSquare();
|
|
|
|
if (hv > eps) return 0;
|
|
/*
|
|
if (hv > maxvalnew)
|
|
maxvalnew = hv;
|
|
*/
|
|
}
|
|
|
|
|
|
// if (possible && 0)
|
|
if (false)
|
|
|
|
for (i = 0; i <= divisions; i++)
|
|
{
|
|
|
|
lambda1 = (double)i/(double)divisions;
|
|
seg1p = Point3d(p1(0)*lambda1+p2(0)*(1.-lambda1),
|
|
p1(1)*lambda1+p2(1)*(1.-lambda1),
|
|
p1(2)*lambda1+p2(2)*(1.-lambda1));
|
|
|
|
|
|
|
|
for (k = 0; k <= divisions; k++)
|
|
{
|
|
lambda2 = (double)k/(double)divisions;
|
|
vptpl = Vec3d(sp1(0)*lambda2+sp2(0)*(1.-lambda2)-seg1p(0),
|
|
sp1(1)*lambda2+sp2(1)*(1.-lambda2)-seg1p(1),
|
|
sp1(2)*lambda2+sp2(2)*(1.-lambda2)-seg1p(2));
|
|
|
|
vlen2 = vptpl.Length2();
|
|
|
|
// if (vlen2 > 0)
|
|
{
|
|
scal = vptpl * sn;
|
|
double hv = scal*scal - sinchartangle2*vlen2;
|
|
|
|
|
|
|
|
/*
|
|
if (hv > maxval)
|
|
maxval = hv;
|
|
*/
|
|
if (hv > eps) return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
// return (maxvalnew < eps);
|
|
}
|
|
|
|
void STLBoundary :: BuildSearchTree()
|
|
{
|
|
Box<2> box2d(Box<2>::EMPTY_BOX);
|
|
Box<3> box3d = geometry->GetBoundingBox();
|
|
|
|
for (size_t i = 0; i < 8; i++)
|
|
box2d.Add ( chart->Project2d (box3d.GetPointNr(i)));
|
|
|
|
searchtree = make_unique<BoxTree<2,INDEX_2>> (box2d);
|
|
// searchtree = nullptr;
|
|
}
|
|
|
|
void STLBoundary :: DeleteSearchTree()
|
|
{
|
|
searchtree = nullptr;
|
|
}
|
|
|
|
|
|
// checks, whether 2d projection intersects
|
|
bool STLBoundary :: TestSegChartNV(const Point3d & p1, const Point3d& p2,
|
|
const Vec3d& sn)
|
|
{
|
|
// static int timerquick = NgProfiler::CreateTimer ("TestSegChartNV-searchtree");
|
|
// static Timer timer("TestSegChartNV"); RegionTimer reg(timer);
|
|
|
|
|
|
Point<2> p2d1 = chart->Project2d (p1);
|
|
Point<2> p2d2 = chart->Project2d (p2);
|
|
|
|
Box<2> box2d;
|
|
box2d.Set (p2d1);
|
|
box2d.Add (p2d2);
|
|
|
|
Line2d l1 (p2d1, p2d2);
|
|
|
|
double eps = 1e-6;
|
|
|
|
auto hasIntersection = [&] (auto i2) NETGEN_LAMBDA_INLINE
|
|
{
|
|
const STLBoundarySeg & seg = boundary_ht[i2];
|
|
|
|
if (seg.IsSmoothEdge()) return false;
|
|
if (!box2d.Intersect (seg.BoundingBox())) return false;
|
|
|
|
const Point<2> & sp1 = seg.P2D1();
|
|
const Point<2> & sp2 = seg.P2D2();
|
|
|
|
Line2d l2 (sp1, sp2);
|
|
double lam1, lam2;
|
|
|
|
int err = CrossPointBarycentric (l1, l2, lam1, lam2);
|
|
bool in1 = (lam1 > eps) && (lam1 < 1-eps);
|
|
bool on1 = (lam1 > -eps) && (lam1 < 1 + eps);
|
|
bool in2 = (lam2 > eps) && (lam2 < 1-eps);
|
|
bool on2 = (lam2 > -eps) && (lam2 < 1 + eps);
|
|
|
|
if(!err && ((on1 && in2) || (on2 && in1)))
|
|
return true;
|
|
return false;
|
|
};
|
|
|
|
if (searchtree)
|
|
{
|
|
bool has_intersection = false;
|
|
searchtree -> GetFirstIntersecting (box2d.PMin(), box2d.PMax(),
|
|
[&] (auto i2) NETGEN_LAMBDA_INLINE
|
|
{
|
|
has_intersection = hasIntersection(i2);
|
|
return has_intersection;
|
|
});
|
|
return !has_intersection;
|
|
}
|
|
else
|
|
{
|
|
for(auto [i2, seg] : boundary_ht)
|
|
if(hasIntersection(i2))
|
|
return false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
STLDoctorParams :: STLDoctorParams()
|
|
{
|
|
drawmeshededges = 1;
|
|
geom_tol_fact = 1E-6;
|
|
longlinefact = 0;
|
|
showexcluded = 1;
|
|
|
|
selectmode = 0;
|
|
edgeselectmode = 0;
|
|
useexternaledges = 0;
|
|
showfaces = 0;
|
|
showtouchedtrigchart = 1;
|
|
showedgecornerpoints = 1;
|
|
conecheck = 1;
|
|
spiralcheck = 1;
|
|
selecttrig = 0;
|
|
nodeofseltrig = 1;
|
|
selectwithmouse = 1;
|
|
showmarkedtrigs = 1;
|
|
dirtytrigfact = 0.001;
|
|
smoothangle = 90;
|
|
smoothnormalsweight = 0.2;
|
|
vicinity = 0;
|
|
showvicinity = 0;
|
|
}
|
|
|
|
|
|
|
|
STLDoctorParams stldoctor;
|
|
|
|
void STLDoctorParams :: Print (ostream & ost) const
|
|
{
|
|
ost << "STL doctor parameters:" << endl
|
|
<< "selecttrig = " << selecttrig << endl
|
|
<< "selectlocalpoint = " << nodeofseltrig << endl
|
|
<< "selectwithmouse = " << selectwithmouse << endl
|
|
<< "showmarkedtrigs = " << showmarkedtrigs << endl
|
|
<< "dirtytrigfact = " << dirtytrigfact << endl
|
|
<< "smoothangle = " << smoothangle << endl;
|
|
}
|
|
|
|
|
|
STLParameters :: STLParameters()
|
|
{
|
|
yangle = 30;
|
|
contyangle = 20;
|
|
edgecornerangle = 60;
|
|
chartangle = 15;
|
|
outerchartangle = 70;
|
|
|
|
usesearchtree = 0;
|
|
atlasminh = 1E-4;
|
|
resthsurfcurvfac = 2;
|
|
resthsurfcurvenable = 0;
|
|
resthatlasfac = 2;
|
|
resthatlasenable = 1;
|
|
resthchartdistfac = 1.2;
|
|
resthchartdistenable = 1;
|
|
resthlinelengthfac = 0.5;
|
|
resthlinelengthenable = 1;
|
|
resthcloseedgefac = 1;
|
|
resthcloseedgeenable = 1;
|
|
resthedgeanglefac = 1;
|
|
resthedgeangleenable = 0;
|
|
resthsurfmeshcurvfac = 1;
|
|
resthsurfmeshcurvenable = 0;
|
|
recalc_h_opt = 1;
|
|
}
|
|
|
|
void STLParameters :: Print (ostream & ost) const
|
|
{
|
|
ost << "STL parameters:" << endl
|
|
<< "yellow angle = " << yangle << endl
|
|
<< "continued yellow angle = " << contyangle << endl
|
|
<< "edgecornerangle = " << edgecornerangle << endl
|
|
<< "chartangle = " << chartangle << endl
|
|
<< "outerchartangle = " << outerchartangle << endl
|
|
<< "restrict h due to ..., enable and safety factor: " << endl
|
|
<< "surface curvature: " << resthsurfcurvenable
|
|
<< ", fac = " << resthsurfcurvfac << endl
|
|
<< "atlas surface curvature: " << resthatlasenable
|
|
<< ", fac = " << resthatlasfac << endl
|
|
<< "chart distance: " << resthchartdistenable
|
|
<< ", fac = " << resthchartdistfac << endl
|
|
<< "line length: " << resthlinelengthenable
|
|
<< ", fac = " << resthlinelengthfac << endl
|
|
<< "close edges: " << resthcloseedgeenable
|
|
<< ", fac = " << resthcloseedgefac << endl
|
|
<< "edge angle: " << resthedgeangleenable
|
|
<< ", fac = " << resthedgeanglefac << endl;
|
|
}
|
|
|
|
|
|
DLL_HEADER extern STLParameters stlparam;
|
|
STLParameters stlparam;
|
|
}
|