Allow circular BSplines to be dimensioned

This commit is contained in:
wandererfan
2018-08-02 20:25:03 -04:00
committed by wmayer
parent b172c234a8
commit c0c36138d7
4 changed files with 259 additions and 9 deletions

View File

@@ -41,8 +41,11 @@
#include <gp_Ax2.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_BezierCurve.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Geometry.hxx>
#include <GeomConvert_BSplineCurveToBezierCurve.hxx>
#include <GeomAPI_PointsToBSpline.hxx>
#include <GeomLProp_CLProps.hxx>
#include <Poly_Polygon3D.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
@@ -58,6 +61,8 @@
#include <Base/Exception.h>
#include <Base/Tools2D.h>
#include <Mod/Part/App/Geometry.h>
#include "Geometry.h"
#include "DrawUtil.h"
@@ -236,7 +241,15 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
result = gen;
delete bspline;
bspline = nullptr;
} else {
} 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;
}
break;
@@ -470,10 +483,35 @@ BSpline::BSpline(const TopoDS_Edge &e)
{
geomType = BSPLINE;
BRepAdaptor_Curve c(e);
isArc = !c.IsClosed();
Handle(Geom_BSplineCurve) cSpline = c.BSpline();
occEdge = e;
Handle(Geom_BSplineCurve) spline;
double f,l;
gp_Pnt s,ePt;
f = c.FirstParameter();
l = c.LastParameter();
gp_Pnt s = c.Value(f);
gp_Pnt m = c.Value((l+f)/2.0);
gp_Pnt ePt = c.Value(l);
startPnt = Base::Vector2d(s.X(), s.Y());
endPnt = Base::Vector2d(ePt.X(), ePt.Y());
midPnt = Base::Vector2d(m.X(), m.Y());
gp_Vec v1(m,s);
gp_Vec v2(m,ePt);
gp_Vec v3(0,0,1);
double a = v3.DotCross(v1,v2);
cw = (a < 0) ? true: false;
startAngle = atan2(startPnt.y,startPnt.x);
if (startAngle < 0) {
startAngle += 2.0 * M_PI;
}
endAngle = atan2(endPnt.y,endPnt.x);
if (endAngle < 0) {
endAngle += 2.0 * M_PI;
}
Standard_Real tol3D = 0.001; //1/1000 of a mm? screen can't resolve this
Standard_Integer maxDegree = 3, maxSegment = 100;
@@ -510,6 +548,8 @@ BSpline::BSpline(const TopoDS_Edge &e)
if (bezier->Degree() > 3) {
Base::Console().Log("Geometry::BSpline - converted curve degree > 3\n");
}
// Base::Console().Message("TRACE - Geo::BSpline - bezier degree: %d bezier poles: %d\n",
// bezier->Degree(),bezier->NbPoles());
tempSegment.poles = bezier->NbPoles();
tempSegment.degree = bezier->Degree();
for (int pole = 1; pole <= tempSegment.poles; ++pole) {
@@ -533,6 +573,109 @@ bool BSpline::isLine()
return result;
}
bool BSpline::isCircle()
{
bool result = false;
double radius;
Base::Vector3d center;
bool isArc = false;
getCircleParms(result,radius,center,isArc);
return result;
}
void BSpline::getCircleParms(bool& isCircle, double& radius, Base::Vector3d& center, bool& isArc)
{
// bool result = false;
double curveLimit = 0.0001;
BRepAdaptor_Curve c(occEdge);
Handle(Geom_BSplineCurve) spline = c.BSpline();
double f,l;
f = c.FirstParameter();
l = c.LastParameter();
double parmRange = fabs(l - f);
int testCount = 6;
double parmStep = parmRange/testCount;
std::vector<double> curvatures;
std::vector<gp_Pnt> centers;
gp_Pnt curveCenter;
double sumCurvature = 0;
Base::Vector3d sumCenter, valueAt;
try {
GeomLProp_CLProps prop(spline,f,3,Precision::Confusion());
curvatures.push_back(prop.Curvature());
sumCurvature += prop.Curvature();
prop.CentreOfCurvature(curveCenter);
centers.push_back(curveCenter);
sumCenter += Base::Vector3d(curveCenter.X(),curveCenter.Y(),curveCenter.Z());
for (int i = 1; i < (testCount - 1); i++) {
prop.SetParameter(parmStep * i);
curvatures.push_back(prop.Curvature());
sumCurvature += prop.Curvature();
prop.CentreOfCurvature(curveCenter);
centers.push_back(curveCenter);
sumCenter += Base::Vector3d(curveCenter.X(),curveCenter.Y(),curveCenter.Z());
}
prop.SetParameter(l);
curvatures.push_back(prop.Curvature());
sumCurvature += prop.Curvature();
prop.CentreOfCurvature(curveCenter);
centers.push_back(curveCenter);
sumCenter += Base::Vector3d(curveCenter.X(),curveCenter.Y(),curveCenter.Z());
}
catch (Standard_Failure& e) {
Base::Console().Log("TechDraw - GEO::BSpline::getCircleParms - CLProps failed\n");
isCircle = false;
return;
// throw Base::RuntimeError(e.GetMessageString());
}
Base::Vector3d avgCenter = sumCenter/testCount;
double errorCenter = 0;
for (auto& c: centers) {
errorCenter += (avgCenter - Base::Vector3d(c.X(), c.Y(), c.Z())).Length();
}
errorCenter = errorCenter/testCount;
double avgCurve = sumCurvature/testCount;
double errorCurve = 0;
for (auto& cv: curvatures) {
errorCurve += fabs(avgCurve - cv); //fabs???
}
errorCurve = errorCurve/testCount;
isArc = !c.IsClosed();
isCircle = false;
if ( errorCurve < curveLimit ) {
isCircle = true;
radius = 1.0/avgCurve;
center = avgCenter;
}
}
bool BSpline::intersectsArc(Base::Vector3d p1,Base::Vector3d p2)
{
bool result = false;
double minDist = -1.0;
gp_Pnt pnt1(p1.x,p1.y,p1.z);
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnt1);
gp_Pnt pnt2(p2.x,p2.y,p2.z);
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnt2);
BRepBuilderAPI_MakeEdge mkEdge(v1,v2);
TopoDS_Edge line = mkEdge.Edge();
BRepExtrema_DistShapeShape extss(occEdge, line);
if (extss.IsDone()) {
int count = extss.NbSolution();
if (count != 0) {
minDist = extss.Value();
if (minDist < Precision::Confusion()) {
result = true;
}
}
}
return result;
}
BezierSegment::BezierSegment(const TopoDS_Edge &e)
{
geomType = BEZIER;