Merge pull request #12602 from FlachyJoe/arc-distance
Sketcher : ArcLength Constraint
This commit is contained in:
@@ -87,6 +87,7 @@ SoDatumLabel::SoDatumLabel()
|
||||
SO_NODE_DEFINE_ENUM_VALUE(Type, ANGLE);
|
||||
SO_NODE_DEFINE_ENUM_VALUE(Type, RADIUS);
|
||||
SO_NODE_DEFINE_ENUM_VALUE(Type, DIAMETER);
|
||||
SO_NODE_DEFINE_ENUM_VALUE(Type, ARCLENGTH);
|
||||
SO_NODE_SET_SF_ENUM_TYPE(datumtype, Type);
|
||||
|
||||
SO_NODE_ADD_FIELD(param1, (0.f));
|
||||
@@ -174,6 +175,9 @@ public:
|
||||
else if (label->datumtype.getValue() == SoDatumLabel::SYMMETRIC) {
|
||||
corners = computeSymmetricBBox();
|
||||
}
|
||||
else if (label->datumtype.getValue() == SoDatumLabel::ARCLENGTH) {
|
||||
corners = computeArcLengthBBox();
|
||||
}
|
||||
|
||||
getBBox(corners, box, center);
|
||||
}
|
||||
@@ -430,6 +434,73 @@ private:
|
||||
return corners;
|
||||
}
|
||||
|
||||
std::vector<SbVec3f> computeArcLengthBBox() const
|
||||
{ SbVec2s imgsize;
|
||||
int nc;
|
||||
int srcw = 1;
|
||||
int srch = 1;
|
||||
|
||||
const unsigned char * dataptr = label->image.getValue(imgsize, nc);
|
||||
if (dataptr) {
|
||||
srcw = imgsize[0];
|
||||
srch = imgsize[1];
|
||||
}
|
||||
|
||||
float aspectRatio = (float) srcw / (float) srch;
|
||||
float imgHeight = scale * (float) (srch);
|
||||
float imgWidth = aspectRatio * imgHeight;
|
||||
|
||||
// Get the points stored in the pnt field
|
||||
const SbVec3f *points = label->pnts.getValues(0);
|
||||
if (label->pnts.getNum() < 3) {
|
||||
return {};
|
||||
}
|
||||
|
||||
SbVec3f ctr = points[0];
|
||||
SbVec3f p1 = points[1];
|
||||
SbVec3f p2 = points[2];
|
||||
|
||||
SbVec3f img1 = SbVec3f(-imgWidth / 2, -imgHeight / 2, 0.f);
|
||||
SbVec3f img2 = SbVec3f(-imgWidth / 2, imgHeight / 2, 0.f);
|
||||
SbVec3f img3 = SbVec3f( imgWidth / 2, -imgHeight / 2, 0.f);
|
||||
SbVec3f img4 = SbVec3f( imgWidth / 2, imgHeight / 2, 0.f);
|
||||
|
||||
//Text orientation
|
||||
SbVec3f dir = (p2 - p1);
|
||||
dir.normalize();
|
||||
SbVec3f normal = SbVec3f (-dir[1], dir[0], 0);
|
||||
float angle = atan2f(dir[1],dir[0]);
|
||||
|
||||
// Rotate through an angle
|
||||
float s = sin(angle);
|
||||
float c = cos(angle);
|
||||
img1 = SbVec3f((img1[0] * c) - (img1[1] * s), (img1[0] * s) + (img1[1] * c), 0.f);
|
||||
img2 = SbVec3f((img2[0] * c) - (img2[1] * s), (img2[0] * s) + (img2[1] * c), 0.f);
|
||||
img3 = SbVec3f((img3[0] * c) - (img3[1] * s), (img3[0] * s) + (img3[1] * c), 0.f);
|
||||
img4 = SbVec3f((img4[0] * c) - (img4[1] * s), (img4[0] * s) + (img4[1] * c), 0.f);
|
||||
|
||||
float length = label->param1.getValue();
|
||||
|
||||
// Text location
|
||||
SbVec3f vm = (p1+p2)/2 - ctr;
|
||||
vm.normalize();
|
||||
SbVec3f textCenter = ctr + vm * (length + imgHeight);
|
||||
img1 += textCenter;
|
||||
img2 += textCenter;
|
||||
img3 += textCenter;
|
||||
img4 += textCenter;
|
||||
|
||||
// Finds the mins and maxes
|
||||
std::vector<SbVec3f> corners;
|
||||
float margin = imgHeight / 4.0F;
|
||||
corners.push_back(textCenter + dir * (imgWidth / 2.0F + margin) - normal * (imgHeight / 2.0F + margin));
|
||||
corners.push_back(textCenter - dir * (imgWidth / 2.0F + margin) - normal * (imgHeight / 2.0F + margin));
|
||||
corners.push_back(textCenter + dir * (imgWidth / 2.0F + margin) + normal * (imgHeight / 2.0F + margin));
|
||||
corners.push_back(textCenter - dir * (imgWidth / 2.0F + margin) + normal * (imgHeight / 2.0F + margin));
|
||||
|
||||
return corners;
|
||||
}
|
||||
|
||||
private:
|
||||
float scale;
|
||||
SoDatumLabel* label;
|
||||
@@ -451,6 +522,7 @@ SbVec3f SoDatumLabel::getLabelTextCenter()
|
||||
const SbVec3f* points = this->pnts.getValues(0);
|
||||
SbVec3f p1 = points[0];
|
||||
SbVec3f p2 = points[1];
|
||||
SbVec3f p3 = points[2];
|
||||
|
||||
if (datumtype.getValue() == SoDatumLabel::DISTANCE ||
|
||||
datumtype.getValue() == SoDatumLabel::DISTANCEX ||
|
||||
@@ -465,6 +537,9 @@ SbVec3f SoDatumLabel::getLabelTextCenter()
|
||||
else if (datumtype.getValue() == SoDatumLabel::ANGLE) {
|
||||
return getLabelTextCenterAngle(p1);
|
||||
}
|
||||
else if (datumtype.getValue() == SoDatumLabel::ARCLENGTH) {
|
||||
return getLabelTextCenterArcLength(p1, p2, p3);
|
||||
}
|
||||
|
||||
return p1;
|
||||
}
|
||||
@@ -525,6 +600,18 @@ SbVec3f SoDatumLabel::getLabelTextCenterAngle(const SbVec3f& p0)
|
||||
return textCenter;
|
||||
}
|
||||
|
||||
SbVec3f SoDatumLabel::getLabelTextCenterArcLength(const SbVec3f& ctr, const SbVec3f& p1, const SbVec3f& p2)
|
||||
{
|
||||
float length = this->param1.getValue();
|
||||
|
||||
// Text location
|
||||
SbVec3f vm = (p1+p2)/2 - ctr;
|
||||
vm.normalize();
|
||||
SbVec3f textCenter = ctr + vm * (length + this->imgHeight);
|
||||
return textCenter;
|
||||
}
|
||||
|
||||
|
||||
void SoDatumLabel::generateDistancePrimitives(SoAction * action, const SbVec3f& p1, const SbVec3f& p2)
|
||||
{
|
||||
SbVec3f dir;
|
||||
@@ -725,6 +812,56 @@ void SoDatumLabel::generateSymmetricPrimitives(SoAction * action, const SbVec3f&
|
||||
this->endShape();
|
||||
}
|
||||
|
||||
void SoDatumLabel::generateArcLengthPrimitives(SoAction * action, const SbVec3f& ctr, const SbVec3f& p1, const SbVec3f& p2)
|
||||
{
|
||||
SbVec3f img1 = SbVec3f(-this->imgWidth / 2, -this->imgHeight / 2, 0.f);
|
||||
SbVec3f img2 = SbVec3f(-this->imgWidth / 2, this->imgHeight / 2, 0.f);
|
||||
SbVec3f img3 = SbVec3f( this->imgWidth / 2, -this->imgHeight / 2, 0.f);
|
||||
SbVec3f img4 = SbVec3f( this->imgWidth / 2, this->imgHeight / 2, 0.f);
|
||||
|
||||
//Text orientation
|
||||
SbVec3f dir = (p2 - p1);
|
||||
dir.normalize();
|
||||
float angle = atan2f(dir[1],dir[0]);
|
||||
|
||||
// Rotate through an angle
|
||||
float s = sin(angle);
|
||||
float c = cos(angle);
|
||||
img1 = SbVec3f((img1[0] * c) - (img1[1] * s), (img1[0] * s) + (img1[1] * c), 0.f);
|
||||
img2 = SbVec3f((img2[0] * c) - (img2[1] * s), (img2[0] * s) + (img2[1] * c), 0.f);
|
||||
img3 = SbVec3f((img3[0] * c) - (img3[1] * s), (img3[0] * s) + (img3[1] * c), 0.f);
|
||||
img4 = SbVec3f((img4[0] * c) - (img4[1] * s), (img4[0] * s) + (img4[1] * c), 0.f);
|
||||
|
||||
//Text location
|
||||
SbVec3f textOffset = getLabelTextCenterArcLength(ctr, p1, p2);
|
||||
img1 += textOffset;
|
||||
img2 += textOffset;
|
||||
img3 += textOffset;
|
||||
img4 += textOffset;
|
||||
|
||||
// Primitive Shape is only for text as this should only be selectable
|
||||
SoPrimitiveVertex pv;
|
||||
|
||||
this->beginShape(action, TRIANGLE_STRIP);
|
||||
|
||||
pv.setNormal( SbVec3f(0.f, 0.f, 1.f) );
|
||||
|
||||
// Set coordinates
|
||||
pv.setPoint( img1 );
|
||||
shapeVertex(&pv);
|
||||
|
||||
pv.setPoint( img2 );
|
||||
shapeVertex(&pv);
|
||||
|
||||
pv.setPoint( img3 );
|
||||
shapeVertex(&pv);
|
||||
|
||||
pv.setPoint( img4 );
|
||||
shapeVertex(&pv);
|
||||
|
||||
this->endShape();
|
||||
}
|
||||
|
||||
void SoDatumLabel::generatePrimitives(SoAction * action)
|
||||
{
|
||||
// Initialisation check (needs something more sensible) prevents an infinite loop bug
|
||||
@@ -735,6 +872,7 @@ void SoDatumLabel::generatePrimitives(SoAction * action)
|
||||
const SbVec3f *points = this->pnts.getValues(0);
|
||||
SbVec3f p1 = points[0];
|
||||
SbVec3f p2 = points[1];
|
||||
SbVec3f p3 = points[2];
|
||||
|
||||
// Change the offset and bounding box parameters depending on Datum Type
|
||||
if (this->datumtype.getValue() == DISTANCE ||
|
||||
@@ -756,6 +894,10 @@ void SoDatumLabel::generatePrimitives(SoAction * action)
|
||||
|
||||
generateSymmetricPrimitives(action, p1, p2);
|
||||
}
|
||||
else if (this->datumtype.getValue() == ARCLENGTH) {
|
||||
|
||||
generateArcLengthPrimitives(action, p1, p2, p3);
|
||||
}
|
||||
}
|
||||
|
||||
void SoDatumLabel::notify(SoNotList * l)
|
||||
@@ -1272,6 +1414,104 @@ void SoDatumLabel::GLRender(SoGLRenderAction * action)
|
||||
glVertex3f(ar5[0], ar5[1], ZCONSTR);
|
||||
glEnd();
|
||||
}
|
||||
else if (this->datumtype.getValue() == ARCLENGTH) {
|
||||
SbVec3f ctr = points[0];
|
||||
SbVec3f p1 = points[1];
|
||||
SbVec3f p2 = points[2];
|
||||
float length = this->param1.getValue();
|
||||
|
||||
float margin = this->imgHeight / 3.0;
|
||||
|
||||
// Angles calculations
|
||||
SbVec3f vc1 = (p1 - ctr);
|
||||
SbVec3f vc2 = (p2 - ctr);
|
||||
|
||||
float startangle = atan2f(vc1[1], vc1[0]);
|
||||
float endangle = atan2f(vc2[1], vc2[0]);
|
||||
if (endangle < startangle)
|
||||
endangle += 2. * M_PI;
|
||||
|
||||
float radius = vc1.length();
|
||||
|
||||
float range = endangle - startangle;
|
||||
|
||||
//Text orientation
|
||||
SbVec3f dir = (p2 - p1);
|
||||
dir.normalize();
|
||||
// Get magnitude of angle between horizontal
|
||||
angle = atan2f(dir[1],dir[0]);
|
||||
if (angle > M_PI_2+M_PI/12) {
|
||||
angle -= (float)M_PI;
|
||||
} else if (angle <= -M_PI_2+M_PI/12) {
|
||||
angle += (float)M_PI;
|
||||
}
|
||||
|
||||
// Text location
|
||||
SbVec3f vm = (p1+p2)/2 - ctr;
|
||||
vm.normalize();
|
||||
textOffset = ctr + vm * (length + this->imgHeight);
|
||||
|
||||
int countSegments = std::max(6, abs(int(50.0 * range / (2 * M_PI))));
|
||||
double segment = range / (countSegments - 1);
|
||||
|
||||
// Draw arc
|
||||
glBegin(GL_LINE_STRIP);
|
||||
|
||||
for (int i=0; i < countSegments; i++) {
|
||||
double theta = startangle + segment*i;
|
||||
SbVec3f v1 = ctr + radius * SbVec3f(cos(theta),sin(theta),0) + (length-radius) * vm;
|
||||
glVertex2f(v1[0],v1[1]);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
//Draw lines
|
||||
SbVec3f pnt1 = p1;
|
||||
SbVec3f pnt2 = p1 + (length-radius) * vm;
|
||||
SbVec3f pnt3 = p2;
|
||||
SbVec3f pnt4 = p2 + (length-radius) * vm;
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(pnt1[0],pnt1[1]);
|
||||
glVertex2f(pnt2[0],pnt2[1]);
|
||||
|
||||
glVertex2f(pnt3[0],pnt3[1]);
|
||||
glVertex2f(pnt4[0],pnt4[1]);
|
||||
glEnd();
|
||||
|
||||
// Create the arrowheads
|
||||
// Direction vectors at arc start and end
|
||||
SbVec3f v1(cos(startangle),sin(startangle),0);
|
||||
SbVec3f v2(cos(endangle),sin(endangle),0);
|
||||
float arrowLength = margin * 2;
|
||||
float arrowWidth = margin * 0.5;
|
||||
|
||||
// Normals for the arrowheads
|
||||
SbVec3f dirStart(v1[1], -v1[0], 0);
|
||||
SbVec3f dirEnd(-v2[1], v2[0], 0);
|
||||
|
||||
// Calculate arrowhead points for start angle
|
||||
SbVec3f startArrowBase = pnt2;
|
||||
SbVec3f startArrowLeft = startArrowBase - arrowLength * dirStart + arrowWidth * v1;
|
||||
SbVec3f startArrowRight = startArrowBase - arrowLength * dirStart - arrowWidth * v1;
|
||||
|
||||
// Calculate arrowhead points for end angle
|
||||
SbVec3f endArrowBase = pnt4;
|
||||
SbVec3f endArrowLeft = endArrowBase - arrowLength * dirEnd + arrowWidth * v2;
|
||||
SbVec3f endArrowRight = endArrowBase - arrowLength * dirEnd - arrowWidth * v2;
|
||||
|
||||
// Draw arrowheads
|
||||
glBegin(GL_TRIANGLES);
|
||||
// Start angle arrowhead
|
||||
glVertex2f(startArrowBase[0], startArrowBase[1]);
|
||||
glVertex2f(startArrowLeft[0], startArrowLeft[1]);
|
||||
glVertex2f(startArrowRight[0], startArrowRight[1]);
|
||||
|
||||
// End angle arrowhead
|
||||
glVertex2f(endArrowBase[0], endArrowBase[1]);
|
||||
glVertex2f(endArrowLeft[0], endArrowLeft[1]);
|
||||
glVertex2f(endArrowRight[0], endArrowRight[1]);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
if (hasText) {
|
||||
const unsigned char * dataptr = this->image.getValue(imgsize, nc);
|
||||
|
||||
@@ -54,7 +54,8 @@ public:
|
||||
DISTANCEY,
|
||||
RADIUS,
|
||||
DIAMETER,
|
||||
SYMMETRIC
|
||||
SYMMETRIC,
|
||||
ARCLENGTH
|
||||
};
|
||||
|
||||
static void initClass();
|
||||
@@ -99,9 +100,11 @@ private:
|
||||
void generateDiameterPrimitives(SoAction * action, const SbVec3f&, const SbVec3f&);
|
||||
void generateAnglePrimitives(SoAction * action, const SbVec3f&);
|
||||
void generateSymmetricPrimitives(SoAction * action, const SbVec3f&, const SbVec3f&);
|
||||
void generateArcLengthPrimitives(SoAction * action, const SbVec3f&, const SbVec3f&, const SbVec3f&);
|
||||
SbVec3f getLabelTextCenterDistance(const SbVec3f&, const SbVec3f&);
|
||||
SbVec3f getLabelTextCenterDiameter(const SbVec3f&, const SbVec3f&);
|
||||
SbVec3f getLabelTextCenterAngle(const SbVec3f&);
|
||||
SbVec3f getLabelTextCenterArcLength(const SbVec3f&, const SbVec3f&, const SbVec3f&);
|
||||
|
||||
private:
|
||||
void drawImage();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user