Merge pull request #12602 from FlachyJoe/arc-distance

Sketcher : ArcLength Constraint
This commit is contained in:
sliptonic
2024-04-01 10:43:35 -05:00
committed by GitHub
11 changed files with 470 additions and 33 deletions

View File

@@ -2162,7 +2162,7 @@ int Sketch::addConstraint(const Constraint* constraint)
c.driving);
}
}
else { // line length
else { // line length, arc length
c.value = new double(constraint->getValue());
if (c.driving) {
FixParameters.push_back(c.value);
@@ -3288,19 +3288,23 @@ int Sketch::addAngleAtPointConstraint(int geoId1,
return ConstraintsCounter;
}
// line length constraint
// line length and arc length constraint
int Sketch::addDistanceConstraint(int geoId, double* value, bool driving)
{
geoId = checkGeoId(geoId);
if (Geoms[geoId].type != Line) {
int tag = ++ConstraintsCounter;
if (Geoms[geoId].type == Line) {
GCS::Line& l = Lines[Geoms[geoId].index];
GCSsys.addConstraintP2PDistance(l.p1, l.p2, value, tag, driving);
}
else if (Geoms[geoId].type == Arc) {
GCS::Arc& a = Arcs[Geoms[geoId].index];
GCSsys.addConstraintArcLength(a, value, tag, driving);
}
else {
return -1;
}
GCS::Line& l = Lines[Geoms[geoId].index];
int tag = ++ConstraintsCounter;
GCSsys.addConstraintP2PDistance(l.p1, l.p2, value, tag, driving);
return ConstraintsCounter;
}

View File

@@ -24,12 +24,14 @@
#pragma warning(disable : 4251)
#endif
#define _USE_MATH_DEFINES
#include <cmath>
#include <algorithm>
#define DEBUG_DERIVS 0
#if DEBUG_DERIVS
#include <cassert>
#endif
#include <cmath>
#include <boost/graph/graph_concepts.hpp>
@@ -3491,4 +3493,90 @@ double ConstraintP2CDistance::grad(double* param)
return deriv * scale;
}
// --------------------------------------------------------
// ConstraintArcLength
ConstraintArcLength::ConstraintArcLength(Arc& a, double* d)
{
this->d = d;
pvec.push_back(d);
this->arc = a;
this->arc.PushOwnParams(pvec);
origpvec = pvec;
pvecChangedFlag = true;
rescale();
}
void ConstraintArcLength::ReconstructGeomPointers()
{
int i = 0;
i++; // skip the first parameter as there is the inline function distance for it
arc.ReconstructOnNewPvec(pvec, i);
pvecChangedFlag = false;
}
ConstraintType ConstraintArcLength::getTypeId()
{
return ArcLength;
}
void ConstraintArcLength::rescale(double coef)
{
scale = coef;
}
void ConstraintArcLength::errorgrad(double* err, double* grad, double* param)
{
if (pvecChangedFlag) {
ReconstructGeomPointers();
}
double rad = *arc.rad;
double endA = *arc.endAngle;
double startA = *arc.startAngle;
// Assume positive angles and CCW arc
while (startA < 0.) {
startA += 2. * M_PI;
}
while (endA < startA) {
endA += 2. * M_PI;
}
if (err) {
*err = rad * (endA - startA) - *distance();
}
else if (grad) {
if (param == distance()) {
// if constraint is not driving it varies on distance().
*grad = -1.;
}
else {
double dRad = param == arc.rad ? 1. : 0.;
double dStartA = param == arc.startAngle ? 1. : 0.;
double dEndA = param == arc.endAngle ? 1. : 0.;
*grad = rad * (dEndA - dStartA) + dRad * (endA - startA);
}
}
}
double ConstraintArcLength::error()
{
double err;
errorgrad(&err, nullptr, nullptr);
return scale * err;
}
double ConstraintArcLength::grad(double* param)
{
if (findParamInPvec(param) == -1) {
return 0.0;
}
double deriv;
errorgrad(nullptr, &deriv, param);
return deriv * scale;
}
} // namespace GCS

View File

@@ -81,7 +81,8 @@ enum ConstraintType
P2CDistance = 32,
AngleViaPointAndParam = 33,
AngleViaPointAndTwoParams = 34,
AngleViaTwoPoints = 35
AngleViaTwoPoints = 35,
ArcLength = 36,
};
enum InternalAlignmentType
@@ -1385,6 +1386,28 @@ public:
double grad(double*) override;
};
// ArcLength
class ConstraintArcLength: public Constraint
{
private:
Arc arc;
double* d;
inline double* distance()
{
return pvec[0];
}
void ReconstructGeomPointers(); // writes pointers in pvec to the parameters of a
void
errorgrad(double* err,
double* grad,
double* param); // error and gradient combined. Values are returned through pointers.
public:
ConstraintArcLength(Arc& a, double* d);
ConstraintType getTypeId() override;
void rescale(double coef = 1.) override;
double error() override;
double grad(double*) override;
};
} // namespace GCS

View File

@@ -889,6 +889,15 @@ int System::addConstraintP2CDistance(Point& p, Circle& c, double* distance, int
return addConstraint(constr);
}
int System::addConstraintArcLength(Arc& a, double* distance, int tagId, bool driving)
{
Constraint* constr = new ConstraintArcLength(a, distance);
constr->setTag(tagId);
constr->setDriving(driving);
return addConstraint(constr);
}
// derived constraints
int System::addConstraintP2PCoincident(Point& p1, Point& p2, int tagId, bool driving)

View File

@@ -462,6 +462,7 @@ public:
double* distance,
int tagId = 0,
bool driving = true);
int addConstraintArcLength(Arc& a, double* dist, int tagId, bool driving = true);
// internal alignment constraints
int addConstraintInternalAlignmentPoint2Ellipse(Ellipse& e,

View File

@@ -243,6 +243,7 @@ public:
double* startAngle;
double* endAngle;
// double *rad; //inherited
// start and end points are computed by an ArcRules constraint
Point start;
Point end;
// Point center; //inherited

View File

@@ -4615,6 +4615,33 @@ void CmdSketcherConstrainDistance::activated(int iMsg)
finishDatumConstraint(this, Obj, true);
}
return;
}
else if (isArcOfCircle(*geom)) {
auto arc = static_cast<const Part::GeomArcOfCircle*>(geom);
double ActLength = arc->getAngle(false) * arc->getRadius();
openCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint"));
Gui::cmdAppObjectArgs(selection[0].getObject(),
"addConstraint(Sketcher.Constraint('Distance',%d,%f))",
GeoId1,
ActLength);
// it is a constraint on a external line, make it non-driving
if (arebothpointsorsegmentsfixed || GeoId1 <= Sketcher::GeoEnum::RefExt
|| constraintCreationMode == Reference) {
const std::vector<Sketcher::Constraint*>& ConStr = Obj->Constraints.getValues();
Gui::cmdAppObjectArgs(selection[0].getObject(),
"setDriving(%d,%s)",
ConStr.size() - 1,
"False");
finishDatumConstraint(this, Obj, false);
}
else {
finishDatumConstraint(this, Obj, true);
}
return;
}
}

View File

@@ -891,6 +891,33 @@ Restart:
pnt1 = lineSeg->getStartPoint();
pnt2 = lineSeg->getEndPoint();
}
else if (isArcOfCircle(*geo)) {
// arc length
auto arc = static_cast<const Part::GeomArcOfCircle*>(geo);
int index = static_cast<int>(ConstraintNodePosition::DatumLabelIndex);
auto* asciiText = static_cast<SoDatumLabel*>(sep->getChild(index));
center1 = arc->getCenter();
pnt1 = arc->getStartPoint();
pnt2 = arc->getEndPoint();
double startAngle, endAngle;
arc->getRange(startAngle, endAngle, /*emulateCCW=*/false);
asciiText->datumtype = SoDatumLabel::ARCLENGTH;
asciiText->param1 = Constr->LabelDistance;
asciiText->string =
SbString(std::string("")
.append(getPresentationString(Constr).toUtf8())
.c_str());
asciiText->pnts.setNum(3);
SbVec3f* verts = asciiText->pnts.startEditing();
verts[0] = SbVec3f(center1.x, center1.y, center1.z);
verts[1] = SbVec3f(pnt1.x, pnt1.y, pnt1.z);
verts[2] = SbVec3f(pnt2.x, pnt2.y, pnt2.z);
asciiText->pnts.finishEditing();
break;
}
else {
break;
}

View File

@@ -1731,6 +1731,18 @@ void ViewProviderSketch::moveConstraint(Sketcher::Constraint* Constr, int constN
// with memory allocation
const std::vector<Part::Geometry*> geomlist = getSolvedSketch().extractGeometry(true, true);
// lambda to finalize the move
auto cleanAndDraw = [this, geomlist](){
// delete the cloned objects
for (Part::Geometry* geomPtr : geomlist) {
if (geomPtr) {
delete geomPtr;
}
}
draw(true, false);
};
#ifdef FC_DEBUG
assert(int(geomlist.size()) == extGeoCount + intGeoCount);
assert((Constr->First >= -extGeoCount && Constr->First < intGeoCount)
@@ -1806,23 +1818,33 @@ void ViewProviderSketch::moveConstraint(Sketcher::Constraint* Constr, int constN
const Part::GeomArcOfCircle* arc = static_cast<const Part::GeomArcOfCircle*>(geo);
double radius = arc->getRadius();
Base::Vector3d center = arc->getCenter();
p1 = center;
double startangle, endangle;
arc->getRange(startangle, endangle, /*emulateCCW=*/true);
double angle = Constr->LabelPosition;
if (angle == 10) {
double startangle, endangle;
arc->getRange(startangle, endangle, /*emulateCCW=*/true);
angle = (startangle + endangle) / 2;
if (Constr->Type == Distance && Constr->Second == GeoEnum::GeoUndef){
//arc length
Base::Vector3d dir = Base::Vector3d(toPos.x, toPos.y, 0.) - arc->getCenter();
Constr->LabelDistance = dir.Length();
cleanAndDraw();
return;
}
else {
Base::Vector3d tmpDir = Base::Vector3d(toPos.x, toPos.y, 0) - p1;
angle = atan2(tmpDir.y, tmpDir.x);
// radius and diameter
p1 = center;
double angle = Constr->LabelPosition;
if (angle == 10) {
angle = (startangle + endangle) / 2;
}
else {
Base::Vector3d tmpDir = Base::Vector3d(toPos.x, toPos.y, 0) - p1;
angle = atan2(tmpDir.y, tmpDir.x);
}
if (Constr->Type == Sketcher::Diameter)
p1 = center - radius * Base::Vector3d(cos(angle), sin(angle), 0.);
p2 = center + radius * Base::Vector3d(cos(angle), sin(angle), 0.);
}
if (Constr->Type == Sketcher::Diameter)
p1 = center - radius * Base::Vector3d(cos(angle), sin(angle), 0.);
p2 = center + radius * Base::Vector3d(cos(angle), sin(angle), 0.);
}
else if (geo->is<Part::GeomCircle>()) {
const Part::GeomCircle* circle = static_cast<const Part::GeomCircle*>(geo);
@@ -1863,7 +1885,6 @@ void ViewProviderSketch::moveConstraint(Sketcher::Constraint* Constr, int constN
}
else
return;
Base::Vector3d vec = Base::Vector3d(toPos.x, toPos.y, 0) - p2;
Base::Vector3d dir;
@@ -1893,14 +1914,7 @@ void ViewProviderSketch::moveConstraint(Sketcher::Constraint* Constr, int constN
moveAngleConstraint(Constr, constNum, toPos);
}
// delete the cloned objects
for (Part::Geometry* geomPtr : geomlist) {
if (geomPtr) {
delete geomPtr;
}
}
draw(true, false);
cleanAndDraw();
}
void ViewProviderSketch::moveAngleConstraint(Sketcher::Constraint* constr, int constNum, const Base::Vector2d& toPos)