Sketcher: Angle constraint: when moving it with mouse, it enables user to switch of supplementary angle.
This commit is contained in:
@@ -1580,13 +1580,13 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2d& toPo
|
||||
if (!isInEditMode())
|
||||
return;
|
||||
|
||||
const std::vector<Sketcher::Constraint*>& constrlist =
|
||||
getSketchObject()->Constraints.getValues();
|
||||
Sketcher::SketchObject* obj = getSketchObject();
|
||||
const std::vector<Sketcher::Constraint*>& constrlist = obj->Constraints.getValues();
|
||||
Constraint* Constr = constrlist[constNum];
|
||||
|
||||
#ifdef FC_DEBUG
|
||||
int intGeoCount = getSketchObject()->getHighestCurveIndex() + 1;
|
||||
int extGeoCount = getSketchObject()->getExternalGeometryCount();
|
||||
int intGeoCount = obj->getHighestCurveIndex() + 1;
|
||||
int extGeoCount = obj->getExternalGeometryCount();
|
||||
#endif
|
||||
|
||||
// with memory allocation
|
||||
@@ -1750,93 +1750,123 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2d& toPo
|
||||
}
|
||||
}
|
||||
else if (Constr->Type == Angle) {
|
||||
|
||||
Base::Vector3d p0(0., 0., 0.);
|
||||
double factor = 0.5;
|
||||
if (Constr->Second != GeoEnum::GeoUndef) {// line to line angle
|
||||
Base::Vector3d dir1, dir2;
|
||||
|
||||
if (Constr->Third == GeoEnum::GeoUndef) {// angle between two lines
|
||||
const Part::Geometry* geo1 = GeoList::getGeometryFromGeoId(geomlist, Constr->First);
|
||||
const Part::Geometry* geo2 =
|
||||
GeoList::getGeometryFromGeoId(geomlist, Constr->Second);
|
||||
|
||||
if (geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId()
|
||||
|| geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId())
|
||||
return;
|
||||
const Part::GeomLineSegment* lineSeg1 =
|
||||
static_cast<const Part::GeomLineSegment*>(geo1);
|
||||
const Part::GeomLineSegment* lineSeg2 =
|
||||
static_cast<const Part::GeomLineSegment*>(geo2);
|
||||
|
||||
bool flip1 = (Constr->FirstPos == Sketcher::PointPos::end);
|
||||
bool flip2 = (Constr->SecondPos == Sketcher::PointPos::end);
|
||||
|
||||
dir1 = (flip1 ? -1. : 1.) * (lineSeg1->getEndPoint() - lineSeg1->getStartPoint());
|
||||
dir2 = (flip2 ? -1. : 1.) * (lineSeg2->getEndPoint() - lineSeg2->getStartPoint());
|
||||
Base::Vector3d pnt1 = flip1 ? lineSeg1->getEndPoint() : lineSeg1->getStartPoint();
|
||||
Base::Vector3d pnt2 = flip2 ? lineSeg2->getEndPoint() : lineSeg2->getStartPoint();
|
||||
|
||||
// line-line intersection
|
||||
{
|
||||
double det = dir1.x * dir2.y - dir1.y * dir2.x;
|
||||
if ((det > 0 ? det : -det) < 1e-10)
|
||||
return;// lines are parallel - constraint unmoveable (DeepSOIC: why?..)
|
||||
double c1 = dir1.y * pnt1.x - dir1.x * pnt1.y;
|
||||
double c2 = dir2.y * pnt2.x - dir2.x * pnt2.y;
|
||||
double x = (dir1.x * c2 - dir2.x * c1) / det;
|
||||
double y = (dir1.y * c2 - dir2.y * c1) / det;
|
||||
// intersection point
|
||||
p0 = Base::Vector3d(x, y, 0);
|
||||
|
||||
Base::Vector3d vec = Base::Vector3d(toPos.x, toPos.y, 0) - p0;
|
||||
factor = factor * Base::sgn<double>((dir1 + dir2) * vec);
|
||||
}
|
||||
}
|
||||
else {// angle-via-point
|
||||
Base::Vector3d p = getSolvedSketch().getPoint(Constr->Third, Constr->ThirdPos);
|
||||
p0 = Base::Vector3d(p.x, p.y, 0);
|
||||
dir1 = getSolvedSketch().calculateNormalAtPoint(Constr->First, p.x, p.y);
|
||||
dir1.RotateZ(-M_PI / 2);// convert to vector of tangency by rotating
|
||||
dir2 = getSolvedSketch().calculateNormalAtPoint(Constr->Second, p.x, p.y);
|
||||
dir2.RotateZ(-M_PI / 2);
|
||||
|
||||
Base::Vector3d vec = Base::Vector3d(toPos.x, toPos.y, 0) - p0;
|
||||
factor = factor * Base::sgn<double>((dir1 + dir2) * vec);
|
||||
}
|
||||
}
|
||||
else if (Constr->First != GeoEnum::GeoUndef) {// line/arc angle
|
||||
const Part::Geometry* geo = GeoList::getGeometryFromGeoId(geomlist, Constr->First);
|
||||
|
||||
if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
|
||||
const Part::GeomLineSegment* lineSeg =
|
||||
static_cast<const Part::GeomLineSegment*>(geo);
|
||||
p0 = (lineSeg->getEndPoint() + lineSeg->getStartPoint()) / 2;
|
||||
}
|
||||
else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
|
||||
const Part::GeomArcOfCircle* arc = static_cast<const Part::GeomArcOfCircle*>(geo);
|
||||
p0 = arc->getCenter();
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
Base::Vector3d vec = Base::Vector3d(toPos.x, toPos.y, 0) - p0;
|
||||
Constr->LabelDistance = factor * vec.Length();
|
||||
moveAngleConstraint(constNum, toPos);
|
||||
}
|
||||
|
||||
// delete the cloned objects
|
||||
for (std::vector<Part::Geometry*>::const_iterator it = geomlist.begin(); it != geomlist.end();
|
||||
++it)
|
||||
if (*it)
|
||||
delete *it;
|
||||
for (Part::Geometry* geomPtr : geomlist) {
|
||||
if (geomPtr) {
|
||||
delete geomPtr;
|
||||
}
|
||||
}
|
||||
|
||||
draw(true, false);
|
||||
}
|
||||
|
||||
void ViewProviderSketch::moveAngleConstraint(int constNum, const Base::Vector2d& toPos)
|
||||
{
|
||||
Sketcher::SketchObject* obj = getSketchObject();
|
||||
const std::vector<Sketcher::Constraint*>& constrlist = obj->Constraints.getValues();
|
||||
Constraint* constr = constrlist[constNum];
|
||||
|
||||
Base::Vector3d p0(0., 0., 0.);
|
||||
double factor = 0.5;
|
||||
if (constr->Second != GeoEnum::GeoUndef) {// line to line angle
|
||||
if (constr->Third == GeoEnum::GeoUndef) {// angle between two lines
|
||||
const Part::Geometry* geo1 = obj->getGeometry(constr->First);
|
||||
const Part::Geometry* geo2 = obj->getGeometry(constr->Second);
|
||||
|
||||
if (!isLineSegment(*geo1) || !isLineSegment(*geo2)) {
|
||||
return;
|
||||
}
|
||||
const auto* lineSeg1 = static_cast<const Part::GeomLineSegment*>(geo1);
|
||||
const auto* lineSeg2 = static_cast<const Part::GeomLineSegment*>(geo2);
|
||||
|
||||
Base::Vector2d l1[2], l2[2];
|
||||
l1[0] = Base::Vector2d(lineSeg1->getStartPoint().x, lineSeg1->getStartPoint().y);
|
||||
l1[1] = Base::Vector2d(lineSeg1->getEndPoint().x, lineSeg1->getEndPoint().y);
|
||||
l2[0] = Base::Vector2d(lineSeg2->getStartPoint().x, lineSeg2->getStartPoint().y);
|
||||
l2[1] = Base::Vector2d(lineSeg2->getEndPoint().x, lineSeg2->getEndPoint().y);
|
||||
|
||||
// First we will check if the angle needs to be reversed to its supplementary
|
||||
bool flip1 = (constr->FirstPos == Sketcher::PointPos::end);
|
||||
bool flip2 = (constr->SecondPos == Sketcher::PointPos::end);
|
||||
Base::Vector2d p11 = flip1 ? l1[1] : l1[0];
|
||||
Base::Vector2d p12 = flip1 ? l1[0] : l1[1];
|
||||
Base::Vector2d p21 = flip2 ? l2[1] : l2[0];
|
||||
Base::Vector2d p22 = flip2 ? l2[0] : l2[1];
|
||||
|
||||
// Get the intersection point in 2d of the two lines if possible
|
||||
Base::Line2d line1(p11, p12);
|
||||
Base::Line2d line2(p21, p22);
|
||||
Base::Vector2d intersection = Base::Vector2d(0., 0.);
|
||||
if (!line1.Intersect(line2, intersection)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Base::Vector2d dir1 = p12 - p11;
|
||||
Base::Vector2d dir2 = p22 - p21;
|
||||
|
||||
Base::Vector2d ap3 = intersection + dir1 + dir2;
|
||||
|
||||
auto isLeftOfLine = [](Base::Vector2d a, Base::Vector2d b, Base::Vector2d c) {
|
||||
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x) > 0;
|
||||
};
|
||||
|
||||
bool sign1 = isLeftOfLine(p11, p12, ap3);
|
||||
bool sign2 = isLeftOfLine(p21, p22, ap3);
|
||||
|
||||
bool sign3 = isLeftOfLine(p11, p12, toPos);
|
||||
bool sign4 = isLeftOfLine(p21, p22, toPos);
|
||||
|
||||
bool reverse = !(sign1 == sign3 && sign2 == sign4) && !(sign1 != sign3 && sign2 != sign4);
|
||||
|
||||
if (reverse) {
|
||||
obj->reverseAngleConstraintToSupplementary(constr, constNum);
|
||||
|
||||
ap3 = intersection + dir1 - dir2; //- dir2 instead fo std::swap(dir1, dir2) and dir1 = -dir1
|
||||
sign1 = isLeftOfLine(p11, p12, ap3);
|
||||
sign2 = isLeftOfLine(p21, p22, ap3);
|
||||
}
|
||||
|
||||
p0 = Base::Vector3d(intersection.x, intersection.y, 0.);
|
||||
factor *= (sign1 == sign3 && sign2 == sign4) ? 1. : -1.;
|
||||
}
|
||||
else {// angle-via-point
|
||||
Base::Vector3d p = getSolvedSketch().getPoint(constr->Third, constr->ThirdPos);
|
||||
p0 = Base::Vector3d(p.x, p.y, 0);
|
||||
Base::Vector3d dir1 = getSolvedSketch().calculateNormalAtPoint(constr->First, p.x, p.y);
|
||||
dir1.RotateZ(-M_PI / 2);// convert to vector of tangency by rotating
|
||||
Base::Vector3d dir2 = getSolvedSketch().calculateNormalAtPoint(constr->Second, p.x, p.y);
|
||||
dir2.RotateZ(-M_PI / 2);
|
||||
|
||||
Base::Vector3d vec = Base::Vector3d(toPos.x, toPos.y, 0) - p0;
|
||||
factor = factor * Base::sgn<double>((dir1 + dir2) * vec);
|
||||
}
|
||||
}
|
||||
else if (constr->First != GeoEnum::GeoUndef) {// line/arc angle
|
||||
const Part::Geometry* geo = obj->getGeometry(constr->First);
|
||||
|
||||
if (isLineSegment(*geo)) {
|
||||
const auto* lineSeg = static_cast<const Part::GeomLineSegment*>(geo);
|
||||
p0 = (lineSeg->getEndPoint() + lineSeg->getStartPoint()) / 2;
|
||||
}
|
||||
else if (isArcOfCircle(*geo)) {
|
||||
const auto* arc = static_cast<const Part::GeomArcOfCircle*>(geo);
|
||||
p0 = arc->getCenter();
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
Base::Vector3d vec = Base::Vector3d(toPos.x, toPos.y, 0) - p0;
|
||||
constr->LabelDistance = factor * vec.Length();
|
||||
}
|
||||
|
||||
bool ViewProviderSketch::isSelectable() const
|
||||
{
|
||||
if (isEditing())
|
||||
|
||||
@@ -755,6 +755,7 @@ private:
|
||||
//@{
|
||||
/// moves a selected constraint
|
||||
void moveConstraint(int constNum, const Base::Vector2d& toPos);
|
||||
void moveAngleConstraint(int constNum, const Base::Vector2d& toPos);
|
||||
|
||||
/// returns whether the sketch is in edit mode.
|
||||
bool isInEditMode() const;
|
||||
|
||||
Reference in New Issue
Block a user