Use circles for circular BSplines

This commit is contained in:
wandererfan
2018-10-19 15:29:16 -04:00
committed by Yorik van Havre
parent 2004653fe4
commit 24f43527f5
2 changed files with 138 additions and 36 deletions

View File

@@ -34,6 +34,8 @@
#include <BRepExtrema_DistShapeShape.hxx>
#include <Precision.hxx>
#include <GCPnts_AbscissaPoint.hxx>
#include <gce_MakeCirc.hxx>
#include <GC_MakeArcOfCircle.hxx>
#include <gp_Lin.hxx>
#include <gp_Circ.hxx>
#include <gp_Elips.hxx>
@@ -46,9 +48,11 @@
#include <Geom_BezierCurve.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Geometry.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <GeomConvert_BSplineCurveToBezierCurve.hxx>
#include <GeomAPI_PointsToBSpline.hxx>
#include <GeomLProp_CLProps.hxx>
#include <GeomAPI_ProjectPointOnCurve.hxx>
#include <Poly_Polygon3D.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
@@ -237,6 +241,9 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
case GeomAbs_BSplineCurve: {
BSpline *bspline = 0;
Generic* gen = NULL;
Circle* circ = nullptr;
AOC* aoc = nullptr;
bool isArc = false;
try {
bspline = new BSpline(edge);
if (bspline->isLine()) {
@@ -244,16 +251,23 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
result = gen;
delete bspline;
bspline = nullptr;
} else if (bspline->isCircle()) {
// bool circ,arc;
// double rad;
// Base::Vector3d center;
// bspline->getCircleParms(circ,rad,center,arc);
// Base::Console().Message("TRACE - GEO;:factory - spline is a Circle - radius: %.3f center: %s\n",
// rad, DrawUtil::formatVector(center).c_str());
result = bspline;
}else {
result = bspline;
} else {
TopoDS_Edge circEdge = bspline->isCircle2(isArc);
if (!circEdge.IsNull()) {
if (isArc) {
aoc = new AOC(circEdge);
result = aoc;
delete bspline;
bspline = nullptr;
} else {
circ = new Circle(circEdge);
result = circ;
delete bspline;
bspline = nullptr;
}
}else {
result = bspline;
}
}
break;
}
@@ -324,7 +338,7 @@ AOE::AOE(const TopoDS_Edge &e) : Ellipse(e)
Circle::Circle(const TopoDS_Edge &e)
{
geomType = CIRCLE;
geomType = CIRCLE; //center, radius
BRepAdaptor_Curve c(e);
occEdge = e;
@@ -571,36 +585,37 @@ bool BSpline::isLine()
BRepAdaptor_Curve c(occEdge);
Handle(Geom_BSplineCurve) spline = c.BSpline();
double f = c.FirstParameter();
double l = c.LastParameter();
gp_Pnt s = c.Value(f);
gp_Pnt e = c.Value(l);
bool samePnt = s.IsEqual(e,FLT_EPSILON);
if (!samePnt) {
Base::Vector3d vs = DrawUtil::gpPnt2V3(s);
Base::Vector3d ve = DrawUtil::gpPnt2V3(e);
double endLength = (vs - ve).Length();
int low = 0;
int high = spline->NbPoles() - 1;
TColgp_Array1OfPnt poles(low,high);
spline->Poles(poles);
double lenTotal = 0.0;
for (int i = 0; i < high; i++) {
gp_Pnt p1 = poles(i);
Base::Vector3d v1 = DrawUtil::gpPnt2V3(p1);
gp_Pnt p2 = poles(i+1);
Base::Vector3d v2 = DrawUtil::gpPnt2V3(p2);
lenTotal += (v2-v1).Length();
}
double f = c.FirstParameter();
double l = c.LastParameter();
gp_Pnt s = c.Value(f);
gp_Pnt e = c.Value(l);
if (DrawUtil::fpCompare(lenTotal,endLength)) {
result = true;
}
bool samePnt = s.IsEqual(e,FLT_EPSILON);
if (!samePnt) {
Base::Vector3d vs = DrawUtil::gpPnt2V3(s);
Base::Vector3d ve = DrawUtil::gpPnt2V3(e);
double endLength = (vs - ve).Length();
int low = 0;
int high = spline->NbPoles() - 1;
TColgp_Array1OfPnt poles(low,high);
spline->Poles(poles);
double lenTotal = 0.0;
for (int i = 0; i < high; i++) {
gp_Pnt p1 = poles(i);
Base::Vector3d v1 = DrawUtil::gpPnt2V3(p1);
gp_Pnt p2 = poles(i+1);
Base::Vector3d v2 = DrawUtil::gpPnt2V3(p2);
lenTotal += (v2-v1).Length();
}
if (DrawUtil::fpCompare(lenTotal,endLength)) {
result = true;
}
}
return result;
}
//obs? used by DVDim for approximate dims
bool BSpline::isCircle()
{
bool result = false;
@@ -608,9 +623,13 @@ bool BSpline::isCircle()
Base::Vector3d center;
bool isArc = false;
getCircleParms(result,radius,center,isArc);
Base::Console().Message("TRACE - GEO::BS::isCircle - result: %d radius: %.3f center: %s isArc %d\n",
result,radius,DrawUtil::formatVector(center).c_str(),isArc);
return result;
}
//obs? used by DVDim for approximate dims
void BSpline::getCircleParms(bool& isCircle, double& radius, Base::Vector3d& center, bool& isArc)
{
// bool result = false;
@@ -680,6 +699,88 @@ void BSpline::getCircleParms(bool& isCircle, double& radius, Base::Vector3d& cen
}
}
// can this BSpline be a circle?
TopoDS_Edge BSpline::isCircle2(bool& arc)
{
TopoDS_Edge result;
BRepAdaptor_Curve c(occEdge);
// find the two ends
Handle(Geom_Curve) curve = c.Curve().Curve();
double f = c.FirstParameter();
double l = c.LastParameter();
gp_Pnt s = c.Value(f);
gp_Pnt e = c.Value(l);
arc = !c.IsClosed();
Handle(Geom_BSplineCurve) spline = c.BSpline();
if (spline->NbPoles() < 5) { //need 5 poles (s-p1-pm-p2-e) for algo
return result; //how to do with fewer poles?
}
// get three points on curve (non extreme poles)
int nb_poles = spline->NbPoles();
gp_Pnt p1 = spline->Pole(2); //OCC numbering starts at 1!!
gp_Pnt p2 = spline->Pole(nb_poles-1);
gp_Pnt pm;
if (nb_poles == 5) {
pm = spline->Pole(3); //5 poles => 2.5 => 2
} else {
pm = spline->Pole(nb_poles / 2);
}
// project three poles onto the curve
GeomAPI_ProjectPointOnCurve proj1;
GeomAPI_ProjectPointOnCurve proj2;
GeomAPI_ProjectPointOnCurve projm;
proj1.Init(p1, curve, f, l);
proj2.Init(p2, curve, f, l);
projm.Init(pm, curve, f, l);
// get projected points
gp_Pnt pc1 = proj1.NearestPoint();
gp_Pnt pc2 = proj2.NearestPoint();
gp_Pnt pcm = projm.NearestPoint();
// make 2 circles and find their radii
gce_MakeCirc gce_circ1 = gce_MakeCirc(s,pc1,pcm); //3 point circle
gp_Circ circle1 = gce_circ1.Value();
double radius1 = circle1.Radius();
gp_Pnt center1 = circle1.Location();
Base::Vector3d vc1 = DrawUtil::gpPnt2V3(center1);
gce_MakeCirc gce_circ2 = gce_MakeCirc(pcm,pc2,e);
gp_Circ circle2 = gce_circ2.Value();
double radius2 = circle2.Radius();
gp_Pnt center2 = circle2.Location();
Base::Vector3d vc2 = DrawUtil::gpPnt2V3(center2);
// test circle creation and compare radii
double radius;
Base::Vector3d center;
if ( (gce_circ1.Status() == gce_Done) &&
(gce_circ2.Status() == gce_Done) &&
(!DrawUtil::fpCompare(radius2,radius1)) ) {
if (arc) {
GC_MakeArcOfCircle makeArc(s,pcm,e);
Handle(Geom_TrimmedCurve) tCurve = makeArc.Value();
BRepBuilderAPI_MakeEdge newEdge(tCurve);
result = newEdge;
} else {
radius = (radius1 + radius2) / 2.0;
center = (vc1 + vc2) / 2.0;
gp_Pnt gCenter(center.x,center.y,center.z);
gp_Ax2 stdZ(gCenter,gp_Dir(0,0,1));
gp_Circ newCirc(stdZ,radius);
BRepBuilderAPI_MakeEdge newEdge(newCirc);
result = newEdge;
}
}
return result;
}
bool BSpline::intersectsArc(Base::Vector3d p1,Base::Vector3d p2)
{
bool result = false;