Create makeAngleBetweenTwoLines and Create Create calculateAngle to remove duplicates

This commit is contained in:
Paddle
2023-10-06 14:41:54 +02:00
committed by abdullahtahiriyo
parent 16dd8fc239
commit 2ea27064d5
2 changed files with 173 additions and 300 deletions

View File

@@ -186,6 +186,132 @@ bool isGeoConcentricCompatible(const Part::Geometry* geo)
return (isEllipse(*geo) || isArcOfEllipse(*geo) || isCircle(*geo) || isArcOfCircle(*geo));
}
/// Makes an angle constraint between 2 lines
void SketcherGui::makeAngleBetweenTwoLines(Sketcher::SketchObject* Obj,
Gui::Command* cmd,
int geoId1,
int geoId2)
{
Sketcher::PointPos posId1 = Sketcher::PointPos::none;
Sketcher::PointPos posId2 = Sketcher::PointPos::none;
double actAngle;
if (!calculateAngle(Obj, geoId1, geoId2, posId1, posId2, actAngle)) {
return;
}
if (actAngle == 0.0) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Parallel lines"),
QObject::tr("An angle constraint cannot be set for two parallel lines."));
return;
}
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add angle constraint"));
Gui::cmdAppObjectArgs(Obj,
"addConstraint(Sketcher.Constraint('Angle',%d,%d,%d,%d,%f))",
geoId1,
static_cast<int>(posId1),
geoId2,
static_cast<int>(posId2),
actAngle);
if (areBothPointsOrSegmentsFixed(Obj, geoId1, geoId2)
|| constraintCreationMode == Reference) {
// it is a constraint on a external line, make it non-driving
const std::vector<Sketcher::Constraint*>& ConStr = Obj->Constraints.getValues();
Gui::cmdAppObjectArgs(Obj, "setDriving(%d,%s)", ConStr.size() - 1, "False");
finishDatumConstraint(cmd, Obj, false);
}
else {
finishDatumConstraint(cmd, Obj, true);
}
}
bool SketcherGui::calculateAngle(Sketcher::SketchObject* Obj, int& GeoId1, int& GeoId2, Sketcher::PointPos& PosId1, Sketcher::PointPos& PosId2, double& ActAngle)
{
const Part::Geometry* geom1 = Obj->getGeometry(GeoId1);
const Part::Geometry* geom2 = Obj->getGeometry(GeoId2);
if (!(geom1->getTypeId() == Part::GeomLineSegment::getClassTypeId()) ||
!(geom2->getTypeId() == Part::GeomLineSegment::getClassTypeId())) {
return false;
}
const Part::GeomLineSegment* lineSeg1 = static_cast<const Part::GeomLineSegment*>(geom1);
const Part::GeomLineSegment* lineSeg2 = static_cast<const Part::GeomLineSegment*>(geom2);
// find the two closest line ends
Base::Vector3d p1[2], p2[2];
p1[0] = lineSeg1->getStartPoint();
p1[1] = lineSeg1->getEndPoint();
p2[0] = lineSeg2->getStartPoint();
p2[1] = lineSeg2->getEndPoint();
// Get the intersection point in 2d of the two lines if possible
Base::Line2d line1(Base::Vector2d(p1[0].x, p1[0].y), Base::Vector2d(p1[1].x, p1[1].y));
Base::Line2d line2(Base::Vector2d(p2[0].x, p2[0].y), Base::Vector2d(p2[1].x, p2[1].y));
Base::Vector2d s;
if (line1.Intersect(line2, s)) {
// get the end points of the line segments that are closest to the intersection point
Base::Vector3d s3d(s.x, s.y, p1[0].z);
if (Base::DistanceP2(s3d, p1[0]) < Base::DistanceP2(s3d, p1[1]))
PosId1 = Sketcher::PointPos::start;
else
PosId1 = Sketcher::PointPos::end;
if (Base::DistanceP2(s3d, p2[0]) < Base::DistanceP2(s3d, p2[1]))
PosId2 = Sketcher::PointPos::start;
else
PosId2 = Sketcher::PointPos::end;
}
else {
// if all points are collinear
double length = DBL_MAX;
for (int i = 0; i <= 1; i++) {
for (int j = 0; j <= 1; j++) {
double tmp = Base::DistanceP2(p2[j], p1[i]);
if (tmp < length) {
length = tmp;
PosId1 = i ? Sketcher::PointPos::end : Sketcher::PointPos::start;
PosId2 = j ? Sketcher::PointPos::end : Sketcher::PointPos::start;
}
}
}
}
Base::Vector3d dir1 = ((PosId1 == Sketcher::PointPos::start) ? 1. : -1.) *
(lineSeg1->getEndPoint() - lineSeg1->getStartPoint());
Base::Vector3d dir2 = ((PosId2 == Sketcher::PointPos::start) ? 1. : -1.) *
(lineSeg2->getEndPoint() - lineSeg2->getStartPoint());
// check if the two lines are parallel
Base::Vector3d dir3 = dir1 % dir2;
if (dir3.Length() < Precision::Intersection()) {
Base::Vector3d dist = (p1[0] - p2[0]) % dir1;
if (dist.Sqr() > Precision::Intersection()) {
ActAngle = 0.0;
return true;
}
}
ActAngle = atan2(dir1.x * dir2.y - dir1.y * dir2.x,
dir1.y * dir2.y + dir1.x * dir2.x);
if (ActAngle < 0) {
ActAngle *= -1;
std::swap(GeoId1, GeoId2);
std::swap(PosId1, PosId2);
}
return true;
}
/// Makes a simple tangency constraint using extra point + tangent via point
/// ellipse => an ellipse
/// geom2 => any of an ellipse, an arc of ellipse, a circle, or an arc (of circle)
@@ -2136,95 +2262,33 @@ protected:
}
void createAngleConstrain(int GeoId1, int GeoId2, Base::Vector2d onSketchPos) {
const Part::Geometry* geom1 = Obj->getGeometry(GeoId1);
const Part::Geometry* geom2 = Obj->getGeometry(GeoId2);
Sketcher::PointPos PosId1 = Sketcher::PointPos::none;
Sketcher::PointPos PosId2 = Sketcher::PointPos::none;
double ActAngle;
if (isLineSegment(*geom1) && isLineSegment(*geom2)) {
auto lineSeg1 = static_cast<const Part::GeomLineSegment*>(geom1);
auto lineSeg2 = static_cast<const Part::GeomLineSegment*>(geom2);
// find the two closest line ends
Sketcher::PointPos PosId1 = Sketcher::PointPos::none;
Sketcher::PointPos PosId2 = Sketcher::PointPos::none;
Base::Vector3d p1[2], p2[2];
p1[0] = lineSeg1->getStartPoint();
p1[1] = lineSeg1->getEndPoint();
p2[0] = lineSeg2->getStartPoint();
p2[1] = lineSeg2->getEndPoint();
// Get the intersection point in 2d of the two lines if possible
Base::Line2d line1(Base::Vector2d(p1[0].x, p1[0].y), Base::Vector2d(p1[1].x, p1[1].y));
Base::Line2d line2(Base::Vector2d(p2[0].x, p2[0].y), Base::Vector2d(p2[1].x, p2[1].y));
Base::Vector2d s;
if (line1.Intersect(line2, s)) {
// get the end points of the line segments that are closest to the intersection point
Base::Vector3d s3d(s.x, s.y, p1[0].z);
if (Base::DistanceP2(s3d, p1[0]) < Base::DistanceP2(s3d, p1[1]))
PosId1 = Sketcher::PointPos::start;
else
PosId1 = Sketcher::PointPos::end;
if (Base::DistanceP2(s3d, p2[0]) < Base::DistanceP2(s3d, p2[1]))
PosId2 = Sketcher::PointPos::start;
else
PosId2 = Sketcher::PointPos::end;
}
else {
// if all points are collinear
double length = DBL_MAX;
for (int i = 0; i <= 1; i++) {
for (int j = 0; j <= 1; j++) {
double tmp = Base::DistanceP2(p2[j], p1[i]);
if (tmp < length) {
length = tmp;
PosId1 = i ? Sketcher::PointPos::end : Sketcher::PointPos::start;
PosId2 = j ? Sketcher::PointPos::end : Sketcher::PointPos::start;
}
}
}
}
Base::Vector3d dir1 = ((PosId1 == Sketcher::PointPos::start) ? 1. : -1.) *
(lineSeg1->getEndPoint() - lineSeg1->getStartPoint());
Base::Vector3d dir2 = ((PosId2 == Sketcher::PointPos::start) ? 1. : -1.) *
(lineSeg2->getEndPoint() - lineSeg2->getStartPoint());
// check if the two lines are parallel, in this case an angle is not possible
Base::Vector3d dir3 = dir1 % dir2;
if (dir3.Length() < Precision::Intersection()) {
Base::Vector3d dist = (p1[0] - p2[0]) % dir1;
if (dist.Sqr() > Precision::Intersection()) {
//distance between 2 points
restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraint"));
if ((selLine[0].GeoId == Sketcher::GeoEnum::VAxis || selLine[0].GeoId == Sketcher::GeoEnum::HAxis)) {
createDistanceConstrain(selLine[1].GeoId, Sketcher::PointPos::start, selLine[0].GeoId, selLine[0].PosId, onSketchPos);
}
else {
createDistanceConstrain(selLine[0].GeoId, Sketcher::PointPos::start, selLine[1].GeoId, selLine[1].PosId, onSketchPos);
}
return;
}
}
double ActAngle = atan2(dir1.x * dir2.y - dir1.y * dir2.x,
dir1.y * dir2.y + dir1.x * dir2.x);
if (ActAngle < 0) {
ActAngle *= -1;
std::swap(GeoId1, GeoId2);
std::swap(PosId1, PosId2);
}
Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Angle',%d,%d,%d,%d,%f)) ",
GeoId1, static_cast<int>(PosId1), GeoId2, static_cast<int>(PosId2), ActAngle);
const std::vector<Sketcher::Constraint*>& ConStr = Obj->Constraints.getValues();
if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2) || constraintCreationMode == Reference) {
// it is a constraint on a external line, make it non-driving
Gui::cmdAppObjectArgs(Obj, "setDriving(%i,%s)", ConStr.size() - 1, "False");
}
numberOfConstraintsCreated++;
moveConstraint(ConStr.size() - 1, onSketchPos);
if (calculateAngle(Obj, GeoId1, GeoId2, PosId1, PosId2, ActAngle)) {
return;
}
if (ActAngle == 0.0) {
//Here we are sure that GeoIds are lines. So false means that lines are parallel, we change to distance
restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraint"));
createDistanceConstrain(selLine[1].GeoId, Sketcher::PointPos::start, selLine[0].GeoId, selLine[0].PosId, onSketchPos);
return;
}
Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Angle',%d,%d,%d,%d,%f)) ",
GeoId1, static_cast<int>(PosId1), GeoId2, static_cast<int>(PosId2), ActAngle);
const std::vector<Sketcher::Constraint*>& ConStr = Obj->Constraints.getValues();
if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2) || constraintCreationMode == Reference) {
// it is a constraint on a external line, make it non-driving
Gui::cmdAppObjectArgs(Obj, "setDriving(%i,%s)", ConStr.size() - 1, "False");
}
numberOfConstraintsCreated++;
moveConstraint(ConStr.size() - 1, onSketchPos);
}
void createArcAngleConstrain(int GeoId, Base::Vector2d onSketchPos) {
@@ -8697,114 +8761,8 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
}
if (isEdge(GeoId2, PosId2)) {// line to line angle
const Part::Geometry* geom1 = Obj->getGeometry(GeoId1);
const Part::Geometry* geom2 = Obj->getGeometry(GeoId2);
if (isLineSegment(*geom1) && isLineSegment(*geom2)) {
auto lineSeg1 = static_cast<const Part::GeomLineSegment*>(geom1);
auto lineSeg2 = static_cast<const Part::GeomLineSegment*>(geom2);
// find the two closest line ends
Sketcher::PointPos PosId1 = Sketcher::PointPos::none;
Sketcher::PointPos PosId2 = Sketcher::PointPos::none;
Base::Vector3d p1[2], p2[2];
p1[0] = lineSeg1->getStartPoint();
p1[1] = lineSeg1->getEndPoint();
p2[0] = lineSeg2->getStartPoint();
p2[1] = lineSeg2->getEndPoint();
// Get the intersection point in 2d of the two lines if possible
Base::Line2d line1(Base::Vector2d(p1[0].x, p1[0].y),
Base::Vector2d(p1[1].x, p1[1].y));
Base::Line2d line2(Base::Vector2d(p2[0].x, p2[0].y),
Base::Vector2d(p2[1].x, p2[1].y));
Base::Vector2d s;
if (line1.Intersect(line2, s)) {
// get the end points of the line segments that are closest to the intersection
// point
Base::Vector3d s3d(s.x, s.y, p1[0].z);
if (Base::DistanceP2(s3d, p1[0]) < Base::DistanceP2(s3d, p1[1])) {
PosId1 = Sketcher::PointPos::start;
}
else {
PosId1 = Sketcher::PointPos::end;
}
if (Base::DistanceP2(s3d, p2[0]) < Base::DistanceP2(s3d, p2[1])) {
PosId2 = Sketcher::PointPos::start;
}
else {
PosId2 = Sketcher::PointPos::end;
}
}
else {
// if all points are collinear
double length = DBL_MAX;
for (int i = 0; i <= 1; i++) {
for (int j = 0; j <= 1; j++) {
double tmp = Base::DistanceP2(p2[j], p1[i]);
if (tmp < length) {
length = tmp;
PosId1 = i ? Sketcher::PointPos::end : Sketcher::PointPos::start;
PosId2 = j ? Sketcher::PointPos::end : Sketcher::PointPos::start;
}
}
}
}
Base::Vector3d dir1 = ((PosId1 == Sketcher::PointPos::start) ? 1. : -1.)
* (lineSeg1->getEndPoint() - lineSeg1->getStartPoint());
Base::Vector3d dir2 = ((PosId2 == Sketcher::PointPos::start) ? 1. : -1.)
* (lineSeg2->getEndPoint() - lineSeg2->getStartPoint());
// check if the two lines are parallel, in this case an angle is not possible
Base::Vector3d dir3 = dir1 % dir2;
if (dir3.Length() < Precision::Intersection()) {
Base::Vector3d dist = (p1[0] - p2[0]) % dir1;
if (dist.Sqr() > Precision::Intersection()) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Parallel lines"),
QObject::tr(
"An angle constraint cannot be set for two parallel lines."));
return;
}
}
double ActAngle =
atan2(dir1.x * dir2.y - dir1.y * dir2.x, dir1.y * dir2.y + dir1.x * dir2.x);
if (ActAngle < 0) {
ActAngle *= -1;
std::swap(GeoId1, GeoId2);
std::swap(PosId1, PosId2);
}
openCommand(QT_TRANSLATE_NOOP("Command", "Add angle constraint"));
Gui::cmdAppObjectArgs(selection[0].getObject(),
"addConstraint(Sketcher.Constraint('Angle',%d,%d,%d,%d,%f))",
GeoId1,
static_cast<int>(PosId1),
GeoId2,
static_cast<int>(PosId2),
ActAngle);
if (bothexternal
|| constraintCreationMode
== Reference) {// it is a constraint on a external line, make it non-driving
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;
}
makeAngleBetweenTwoLines(Obj, this, GeoId1, GeoId2);
return;
}
else if (isEdge(GeoId1, PosId1)) {// line angle or arc angle
if (GeoId1 < 0 && GeoId1 >= Sketcher::GeoEnum::VAxis) {
@@ -8900,110 +8858,7 @@ void CmdSketcherConstrainAngle::applyConstraint(std::vector<SelIdPair>& selSeq,
GeoId1 = selSeq.at(0).GeoId;
GeoId2 = selSeq.at(1).GeoId;
const Part::Geometry* geom1 = Obj->getGeometry(GeoId1);
const Part::Geometry* geom2 = Obj->getGeometry(GeoId2);
if (isLineSegment(*geom1) && isLineSegment(*geom2)) {
auto lineSeg1 = static_cast<const Part::GeomLineSegment*>(geom1);
auto lineSeg2 = static_cast<const Part::GeomLineSegment*>(geom2);
// find the two closest line ends
Sketcher::PointPos PosId1 = Sketcher::PointPos::none;
Sketcher::PointPos PosId2 = Sketcher::PointPos::none;
Base::Vector3d p1[2], p2[2];
p1[0] = lineSeg1->getStartPoint();
p1[1] = lineSeg1->getEndPoint();
p2[0] = lineSeg2->getStartPoint();
p2[1] = lineSeg2->getEndPoint();
// Get the intersection point in 2d of the two lines if possible
Base::Line2d line1(Base::Vector2d(p1[0].x, p1[0].y),
Base::Vector2d(p1[1].x, p1[1].y));
Base::Line2d line2(Base::Vector2d(p2[0].x, p2[0].y),
Base::Vector2d(p2[1].x, p2[1].y));
Base::Vector2d s;
if (line1.Intersect(line2, s)) {
// get the end points of the line segments that are closest to the intersection
// point
Base::Vector3d s3d(s.x, s.y, p1[0].z);
if (Base::DistanceP2(s3d, p1[0]) < Base::DistanceP2(s3d, p1[1])) {
PosId1 = Sketcher::PointPos::start;
}
else {
PosId1 = Sketcher::PointPos::end;
}
if (Base::DistanceP2(s3d, p2[0]) < Base::DistanceP2(s3d, p2[1])) {
PosId2 = Sketcher::PointPos::start;
}
else {
PosId2 = Sketcher::PointPos::end;
}
}
else {
// if all points are collinear
double length = DBL_MAX;
for (int i = 0; i <= 1; i++) {
for (int j = 0; j <= 1; j++) {
double tmp = Base::DistanceP2(p2[j], p1[i]);
if (tmp < length) {
length = tmp;
PosId1 = i ? Sketcher::PointPos::end : Sketcher::PointPos::start;
PosId2 = j ? Sketcher::PointPos::end : Sketcher::PointPos::start;
}
}
}
}
Base::Vector3d dir1 = ((PosId1 == Sketcher::PointPos::start) ? 1. : -1.)
* (lineSeg1->getEndPoint() - lineSeg1->getStartPoint());
Base::Vector3d dir2 = ((PosId2 == Sketcher::PointPos::start) ? 1. : -1.)
* (lineSeg2->getEndPoint() - lineSeg2->getStartPoint());
// check if the two lines are parallel, in this case an angle is not possible
Base::Vector3d dir3 = dir1 % dir2;
if (dir3.Length() < Precision::Intersection()) {
Base::Vector3d dist = (p1[0] - p2[0]) % dir1;
if (dist.Sqr() > Precision::Intersection()) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Parallel lines"),
QObject::tr(
"An angle constraint cannot be set for two parallel lines."));
return;
}
}
double ActAngle =
atan2(dir1.x * dir2.y - dir1.y * dir2.x, dir1.y * dir2.y + dir1.x * dir2.x);
if (ActAngle < 0) {
ActAngle *= -1;
std::swap(GeoId1, GeoId2);
std::swap(PosId1, PosId2);
}
openCommand(QT_TRANSLATE_NOOP("Command", "Add angle constraint"));
Gui::cmdAppObjectArgs(Obj,
"addConstraint(Sketcher.Constraint('Angle',%d,%d,%d,%d,%f))",
GeoId1,
static_cast<int>(PosId1),
GeoId2,
static_cast<int>(PosId2),
ActAngle);
if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2)
|| constraintCreationMode == Reference) {
// it is a constraint on a external line, make it non-driving
const std::vector<Sketcher::Constraint*>& ConStr = Obj->Constraints.getValues();
Gui::cmdAppObjectArgs(Obj, "setDriving(%d,%s)", ConStr.size() - 1, "False");
finishDatumConstraint(this, Obj, false);
}
else {
finishDatumConstraint(this, Obj, true);
}
return;
}
makeAngleBetweenTwoLines(Obj, this, GeoId1, GeoId2);
return;
}
case 5:// {SelEdge, SelVertexOrRoot, SelEdgeOrAxis}

View File

@@ -27,12 +27,30 @@
#include <Mod/Sketcher/App/Constraint.h>
#include <Mod/Sketcher/App/SketchObject.h>
namespace Gui
{
class Command;
}
namespace SketcherGui
{
// These functions are declared here to promote code reuse from other modules
/// Makes an angle constraint between 2 lines
void makeAngleBetweenTwoLines(Sketcher::SketchObject* Obj,
Gui::Command* cmd,
int geoId1,
int geoId2);
// Find the angle between two lines. Return false if geoIds are not lines.
bool calculateAngle(Sketcher::SketchObject* Obj,
int& geoId1,
int& geoId2,
Sketcher::PointPos& PosId1,
Sketcher::PointPos& PosId2,
double& ActAngle);
/// Makes a tangency constraint using external construction line between
/// ellipse => an ellipse
/// geom2 => any of an ellipse, an arc of ellipse, a circle, or an arc (of circle)