Allow circular BSplines to be dimensioned

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

View File

@@ -268,6 +268,31 @@ App::DocumentObjectExecReturn *DrawViewDimension::execute(void)
pts.onCurve.first = pts.center + Base::Vector3d(1,0,0) * circle->radius; //arbitrary point on edge
pts.onCurve.second = pts.center + Base::Vector3d(-1,0,0) * circle->radius; //arbitrary point on edge
}
} else if (base && base->geomType == TechDrawGeometry::GeomType::BSPLINE) {
TechDrawGeometry::BSpline* spline = static_cast<TechDrawGeometry::BSpline*> (base);
if (spline->isCircle()) {
bool circ,arc;
double rad;
Base::Vector3d center;
spline->getCircleParms(circ,rad,center,arc);
pts.center = Base::Vector3d(center.x,center.y,0.0);
pts.radius = rad;
pts.arcEnds.first = Base::Vector3d(spline->startPnt.x,spline->startPnt.y,0.0);
pts.arcEnds.second = Base::Vector3d(spline->endPnt.x,spline->endPnt.y,0.0);
pts.midArc = Base::Vector3d(spline->midPnt.x,spline->midPnt.y,0.0);
pts.isArc = arc;
pts.arcCW = spline->cw;
if (arc) {
pts.onCurve.first = Base::Vector3d(spline->midPnt.x,spline->midPnt.y,0.0);
} else {
pts.onCurve.first = pts.center + Base::Vector3d(1,0,0) * rad; //arbitrary point on edge
pts.onCurve.second = pts.center + Base::Vector3d(-1,0,0) * rad; //arbitrary point on edge
}
} else {
//fubar - can't have non-circular spline as target of Diameter dimension
Base::Console().Error("Dimension %s refers to invalid BSpline\n",getNameInDocument());
return App::DocumentObject::StdReturn;
}
} else {
Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument());
return App::DocumentObject::StdReturn;
@@ -285,7 +310,6 @@ App::DocumentObjectExecReturn *DrawViewDimension::execute(void)
(base && base->geomType == TechDrawGeometry::GeomType::ARCOFCIRCLE)) {
circle = static_cast<TechDrawGeometry::Circle*> (base);
pts.center = Base::Vector3d(circle->center.x,circle->center.y,0.0);
pts.center = Base::Vector3d(circle->center.x,circle->center.y,0.0);
pts.radius = circle->radius;
if (base->geomType == TechDrawGeometry::GeomType::ARCOFCIRCLE) {
TechDrawGeometry::AOC* aoc = static_cast<TechDrawGeometry::AOC*> (circle);
@@ -300,6 +324,31 @@ App::DocumentObjectExecReturn *DrawViewDimension::execute(void)
pts.onCurve.first = pts.center + Base::Vector3d(1,0,0) * circle->radius; //arbitrary point on edge
pts.onCurve.second = pts.center + Base::Vector3d(-1,0,0) * circle->radius; //arbitrary point on edge
}
} else if (base && base->geomType == TechDrawGeometry::GeomType::BSPLINE) {
TechDrawGeometry::BSpline* spline = static_cast<TechDrawGeometry::BSpline*> (base);
if (spline->isCircle()) {
bool circ,arc;
double rad;
Base::Vector3d center;
spline->getCircleParms(circ,rad,center,arc);
pts.center = Base::Vector3d(center.x,center.y,0.0);
pts.radius = rad;
pts.arcEnds.first = Base::Vector3d(spline->startPnt.x,spline->startPnt.y,0.0);
pts.arcEnds.second = Base::Vector3d(spline->endPnt.x,spline->endPnt.y,0.0);
pts.midArc = Base::Vector3d(spline->midPnt.x,spline->midPnt.y,0.0);
pts.isArc = arc;
pts.arcCW = spline->cw;
if (arc) {
pts.onCurve.first = Base::Vector3d(spline->midPnt.x,spline->midPnt.y,0.0);
} else {
pts.onCurve.first = pts.center + Base::Vector3d(1,0,0) * rad; //arbitrary point on edge
pts.onCurve.second = pts.center + Base::Vector3d(-1,0,0) * rad; //arbitrary point on edge
}
} else {
//fubar - can't have non-circular spline as target of Diameter dimension
Base::Console().Error("Dimension %s refers to invalid BSpline\n",getNameInDocument());
return App::DocumentObject::StdReturn;
}
} else {
Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument());
return App::DocumentObject::StdReturn;
@@ -760,7 +809,15 @@ bool DrawViewDimension::leaderIntersectsArc(Base::Vector3d s, Base::Vector3d poi
if (aoc->intersectsArc(s,pointOnCircle)) {
result = true;
}
} else if( base && base->geomType == TechDrawGeometry::GeomType::BSPLINE ) {
TechDrawGeometry::BSpline* spline = static_cast<TechDrawGeometry::BSpline*> (base);
if (spline->isCircle()) {
if (spline->intersectsArc(s,pointOnCircle)) {
result = true;
}
}
}
return result;
}

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;

View File

@@ -181,7 +181,19 @@ class TechDrawExport BSpline: public BaseGeom
~BSpline() = default;
public:
Base::Vector2d startPnt;
Base::Vector2d endPnt;
Base::Vector2d midPnt;
double startAngle;
double endAngle;
/// Arc is drawn clockwise from startAngle to endAngle if true, counterclockwise if false
bool cw;
bool isArc;
bool isLine(void);
bool isCircle(void);
void getCircleParms(bool& isCircle, double& radius, Base::Vector3d& center, bool& isArc);
bool intersectsArc(Base::Vector3d p1,Base::Vector3d p2);
std::vector<BezierSegment> segments;
};

View File

@@ -75,7 +75,9 @@ enum EdgeType{
isVertical,
isDiagonal,
isCircle,
isCurve,
isEllipse,
isBSplineCircle,
isBSpline,
isAngle
};
@@ -280,6 +282,18 @@ void CmdTechDrawNewRadiusDimension::activated(int iMsg)
if (edgeType == isCircle) {
objs.push_back(objFeat);
subs.push_back(SubNames[0]);
} else if (edgeType == isBSplineCircle) {
QMessageBox::StandardButton result =
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection Warning"),
QObject::tr("Selected edge is a BSpline. Radius will be approximate."),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Cancel);
if (result == QMessageBox::Ok) {
objs.push_back(objFeat);
subs.push_back(SubNames[0]);
} else {
return;
}
} else {
std::stringstream edgeMsg;
edgeMsg << "Can't make a radius Dimension from this selection (edge type: " << _edgeTypeToText(edgeType) << ")";
@@ -368,6 +382,18 @@ void CmdTechDrawNewDiameterDimension::activated(int iMsg)
if (edgeType == isCircle) {
objs.push_back(objFeat);
subs.push_back(SubNames[0]);
} else if (edgeType == isBSplineCircle) {
QMessageBox::StandardButton result =
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection Warning"),
QObject::tr("Selected edge is a BSpline. Diameter will be approximate."),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Cancel);
if (result == QMessageBox::Ok) {
objs.push_back(objFeat);
subs.push_back(SubNames[0]);
} else {
return;
}
} else {
std::stringstream edgeMsg;
edgeMsg << "Can't make a diameter Dimension from this selection (edge type: " << _edgeTypeToText(edgeType) << ")";
@@ -1020,9 +1046,15 @@ int _isValidSingleEdge(Gui::Command* cmd) {
geom->geomType == TechDrawGeometry::ARCOFCIRCLE ) {
edgeType = isCircle;
} else if (geom->geomType == TechDrawGeometry::ELLIPSE ||
geom->geomType == TechDrawGeometry::ARCOFELLIPSE ||
geom->geomType == TechDrawGeometry::BSPLINE) {
edgeType = isCurve;
geom->geomType == TechDrawGeometry::ARCOFELLIPSE) {
edgeType = isEllipse;
} else if (geom->geomType == TechDrawGeometry::BSPLINE) {
TechDrawGeometry::BSpline* spline = static_cast<TechDrawGeometry::BSpline*>(geom);
if (spline->isCircle()) {
edgeType = isBSplineCircle;
} else {
edgeType = isBSpline;
}
} else {
edgeType = isInvalid;
}
@@ -1154,8 +1186,14 @@ char* _edgeTypeToText(int e)
case isCircle:
result = "circle";
break;
case isCurve:
result = "curve";
case isEllipse:
result = "ellipse";
break;
case isBSpline:
result = "bspline";
break;
case isBSplineCircle:
result = "circular bspline";
break;
case isAngle:
result = "angle";