Allow circular BSplines to be dimensioned
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user