diff --git a/src/Mod/PartDesign/PartDesignTests/TestTopologicalNamingProblem.py b/src/Mod/PartDesign/PartDesignTests/TestTopologicalNamingProblem.py index d3bb6e483e..26d406ec50 100644 --- a/src/Mod/PartDesign/PartDesignTests/TestTopologicalNamingProblem.py +++ b/src/Mod/PartDesign/PartDesignTests/TestTopologicalNamingProblem.py @@ -2149,10 +2149,10 @@ class TestTopologicalNamingProblem(unittest.TestCase): doc.recompute() doc.Pad.Visibility = False doc.Sketch001.Visibility = False - doc.Sketch.movePoint(3, 0, App.Vector(-5, 0, 0), 1) - doc.Sketch.movePoint(0, 0, App.Vector(0.000000, -5, 0), 1) - doc.Sketch.movePoint(1, 0, App.Vector(-5, 0.000000, 0), 1) - doc.Sketch.movePoint(2, 0, App.Vector(-0, -5, 0), 1) + doc.Sketch.moveGeometry(3, 0, App.Vector(-5, 0, 0), 1) + doc.Sketch.moveGeometry(0, 0, App.Vector(0.000000, -5, 0), 1) + doc.Sketch.moveGeometry(1, 0, App.Vector(-5, 0.000000, 0), 1) + doc.Sketch.moveGeometry(2, 0, App.Vector(-0, -5, 0), 1) doc.recompute() # If Sketch001 is still at the right start point, we are good. self.assertTrue(doc.Sketch001.AttachmentOffset.Matrix == App.Matrix()) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index a12383efe2..e67965bf6f 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -4765,307 +4765,260 @@ int Sketch::internalSolve(std::string& solvername, int level) return ret; } -int Sketch::initMove(int geoId, PointPos pos, bool fine) +int Sketch::initMove(std::vector geoEltIds, bool fine) { - isFine = fine; - - geoId = checkGeoId(geoId); - - clearTemporaryConstraints(); - - // don't try to move sketches that contain conflicting constraints if (hasConflicts()) { + // don't try to move sketches that contain conflicting constraints isInitMove = false; return -1; } + isFine = fine; - if (Geoms[geoId].type == Point) { - if (pos == PointPos::start) { - GCS::Point& point = Points[Geoms[geoId].startPointId]; - GCS::Point p0; - MoveParameters.resize(2); // px,py - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *point.x; - *p0.y = *point.y; - GCSsys.addConstraintP2PCoincident(p0, point, GCS::DefaultTemporaryConstraint); - } - } - else if (Geoms[geoId].type == Line) { - if (pos == PointPos::start || pos == PointPos::end) { - MoveParameters.resize(2); // x,y - GCS::Point p0; - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - if (pos == PointPos::start) { - GCS::Point& p = Points[Geoms[geoId].startPointId]; - *p0.x = *p.x; - *p0.y = *p.y; - GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); - } - else if (pos == PointPos::end) { - GCS::Point& p = Points[Geoms[geoId].endPointId]; - *p0.x = *p.x; - *p0.y = *p.y; - GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); - } - } - else if (pos == PointPos::none || pos == PointPos::mid) { - MoveParameters.resize(4); // x1,y1,x2,y2 - GCS::Point p1, p2; - p1.x = &MoveParameters[0]; - p1.y = &MoveParameters[1]; - p2.x = &MoveParameters[2]; - p2.y = &MoveParameters[3]; - GCS::Line& l = Lines[Geoms[geoId].index]; - *p1.x = *l.p1.x; - *p1.y = *l.p1.y; - *p2.x = *l.p2.x; - *p2.y = *l.p2.y; - GCSsys.addConstraintP2PCoincident(p1, l.p1, GCS::DefaultTemporaryConstraint); - GCSsys.addConstraintP2PCoincident(p2, l.p2, GCS::DefaultTemporaryConstraint); - } - } - else if (Geoms[geoId].type == Circle) { - GCS::Point& center = Points[Geoms[geoId].midPointId]; - GCS::Point p0, p1; - if (pos == PointPos::mid) { - MoveParameters.resize(2); // cx,cy - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *center.x; - *p0.y = *center.y; - GCSsys.addConstraintP2PCoincident(p0, center, GCS::DefaultTemporaryConstraint); - } - else if (pos == PointPos::none) { - // bool pole = GeometryFacade::isInternalType(Geoms[geoId].geo, - // InternalType::BSplineControlPoint); - MoveParameters.resize(4); // x,y,cx,cy - For poles blocking the center - GCS::Circle& c = Circles[Geoms[geoId].index]; - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *center.x; - *p0.y = *center.y + *c.rad; - GCSsys.addConstraintPointOnCircle(p0, c, GCS::DefaultTemporaryConstraint); - p1.x = &MoveParameters[2]; - p1.y = &MoveParameters[3]; - *p1.x = *center.x; - *p1.y = *center.y; - int i = GCSsys.addConstraintP2PCoincident(p1, center, GCS::DefaultTemporaryConstraint); - GCSsys.rescaleConstraint(i - 1, 0.01); - GCSsys.rescaleConstraint(i, 0.01); - } - } - else if (Geoms[geoId].type == Ellipse) { + clearTemporaryConstraints(); - GCS::Point& center = Points[Geoms[geoId].midPointId]; - GCS::Point p0, p1; - if (pos == PointPos::mid || pos == PointPos::none) { - MoveParameters.resize(2); // cx,cy - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *center.x; - *p0.y = *center.y; + MoveParameters.clear(); - GCSsys.addConstraintP2PCoincident(p0, center, GCS::DefaultTemporaryConstraint); - } - } - else if (Geoms[geoId].type == ArcOfEllipse) { - - GCS::Point& center = Points[Geoms[geoId].midPointId]; - GCS::Point p0, p1; - if (pos == PointPos::mid || pos == PointPos::none) { - MoveParameters.resize(2); // cx,cy - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *center.x; - *p0.y = *center.y; - GCSsys.addConstraintP2PCoincident(p0, center, GCS::DefaultTemporaryConstraint); - } - else if (pos == PointPos::start || pos == PointPos::end) { - - MoveParameters.resize(4); // x,y,cx,cy - if (pos == PointPos::start || pos == PointPos::end) { - GCS::Point& p = (pos == PointPos::start) ? Points[Geoms[geoId].startPointId] - : Points[Geoms[geoId].endPointId]; - ; - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *p.x; - *p0.y = *p.y; - - GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); - } - - p1.x = &MoveParameters[2]; - p1.y = &MoveParameters[3]; - *p1.x = *center.x; - *p1.y = *center.y; - - int i = GCSsys.addConstraintP2PCoincident(p1, center, GCS::DefaultTemporaryConstraint); - GCSsys.rescaleConstraint(i - 1, 0.01); - GCSsys.rescaleConstraint(i, 0.01); - } - } - else if (Geoms[geoId].type == ArcOfHyperbola) { - - GCS::Point& center = Points[Geoms[geoId].midPointId]; - GCS::Point p0, p1; - if (pos == PointPos::mid || pos == PointPos::none) { - MoveParameters.resize(2); // cx,cy - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *center.x; - *p0.y = *center.y; - - GCSsys.addConstraintP2PCoincident(p0, center, GCS::DefaultTemporaryConstraint); - } - else if (pos == PointPos::start || pos == PointPos::end) { - - MoveParameters.resize(4); // x,y,cx,cy - if (pos == PointPos::start || pos == PointPos::end) { - GCS::Point& p = (pos == PointPos::start) ? Points[Geoms[geoId].startPointId] - : Points[Geoms[geoId].endPointId]; - ; - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *p.x; - *p0.y = *p.y; - - GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); - } - p1.x = &MoveParameters[2]; - p1.y = &MoveParameters[3]; - *p1.x = *center.x; - *p1.y = *center.y; - - int i = GCSsys.addConstraintP2PCoincident(p1, center, GCS::DefaultTemporaryConstraint); - GCSsys.rescaleConstraint(i - 1, 0.01); - GCSsys.rescaleConstraint(i, 0.01); - } - } - else if (Geoms[geoId].type == ArcOfParabola) { - - GCS::Point& center = Points[Geoms[geoId].midPointId]; - GCS::Point p0, p1; - if (pos == PointPos::mid || pos == PointPos::none) { - MoveParameters.resize(2); // cx,cy - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *center.x; - *p0.y = *center.y; - - GCSsys.addConstraintP2PCoincident(p0, center, GCS::DefaultTemporaryConstraint); - } - else if (pos == PointPos::start || pos == PointPos::end) { - - MoveParameters.resize(4); // x,y,cx,cy - if (pos == PointPos::start || pos == PointPos::end) { - GCS::Point& p = (pos == PointPos::start) ? Points[Geoms[geoId].startPointId] - : Points[Geoms[geoId].endPointId]; - ; - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *p.x; - *p0.y = *p.y; - - GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); - } - p1.x = &MoveParameters[2]; - p1.y = &MoveParameters[3]; - *p1.x = *center.x; - *p1.y = *center.y; - - int i = GCSsys.addConstraintP2PCoincident(p1, center, GCS::DefaultTemporaryConstraint); - GCSsys.rescaleConstraint(i - 1, 0.01); - GCSsys.rescaleConstraint(i, 0.01); - } - } - else if (Geoms[geoId].type == BSpline) { - if (pos == PointPos::start || pos == PointPos::end) { - MoveParameters.resize(2); // x,y - GCS::Point p0; - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - if (pos == PointPos::start) { - GCS::Point& p = Points[Geoms[geoId].startPointId]; - *p0.x = *p.x; - *p0.y = *p.y; - GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); - } - else if (pos == PointPos::end) { - GCS::Point& p = Points[Geoms[geoId].endPointId]; - *p0.x = *p.x; - *p0.y = *p.y; - GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); - } - } - else if (pos == PointPos::none || pos == PointPos::mid) { + // We need to reserve enough size in the vec or the dynamic resizing + // (emplace_back in the for loop below) will trigger reallocation. + // Which will corrupt pointers we're storing. + size_t reserveSize = 0; + for (auto& pair : geoEltIds) { + int geoId = checkGeoId(pair.GeoId); + Sketcher::PointPos pos = pair.Pos; + if (Geoms[geoId].type == BSpline && (pos == PointPos::none || pos == PointPos::mid)) { GCS::BSpline& bsp = BSplines[Geoms[geoId].index]; - MoveParameters.resize(bsp.poles.size() * 2); // x0,y0,x1,y1,....xp,yp - - int mvindex = 0; - for (std::vector::iterator it = bsp.poles.begin(); it != bsp.poles.end(); - it++, mvindex++) { - GCS::Point p1; - p1.x = &MoveParameters[mvindex]; - mvindex++; - p1.y = &MoveParameters[mvindex]; - - *p1.x = *(*it).x; - *p1.y = *(*it).y; - - GCSsys.addConstraintP2PCoincident(p1, (*it), GCS::DefaultTemporaryConstraint); - } + reserveSize += bsp.poles.size() * 2; + } + else { + reserveSize += 6; // 6 is the max case for all other cases. } } - else if (Geoms[geoId].type == Arc) { - GCS::Point& center = Points[Geoms[geoId].midPointId]; - GCS::Point p0, p1; - if (pos == PointPos::mid) { - MoveParameters.resize(2); // cx,cy - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *center.x; - *p0.y = *center.y; - GCSsys.addConstraintP2PCoincident(p0, center, GCS::DefaultTemporaryConstraint); + MoveParameters.reserve(reserveSize); + + for (auto& pair : geoEltIds) { + int geoId = checkGeoId(pair.GeoId); + Sketcher::PointPos pos = pair.Pos; + + if (Geoms[geoId].type == Point) { + if (pos == PointPos::start) { + GCS::Point& point = Points[Geoms[geoId].startPointId]; + GCS::Point p0; + p0.x = &MoveParameters.emplace_back(*point.x); + p0.y = &MoveParameters.emplace_back(*point.y); + GCSsys.addConstraintP2PCoincident(p0, point, GCS::DefaultTemporaryConstraint); + } } - else if (pos == PointPos::start || pos == PointPos::end || pos == PointPos::none) { - MoveParameters.resize(4); // x,y,cx,cy + else if (Geoms[geoId].type == Line) { if (pos == PointPos::start || pos == PointPos::end) { - GCS::Point& p = (pos == PointPos::start) ? Points[Geoms[geoId].startPointId] - : Points[Geoms[geoId].endPointId]; - ; - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *p.x; - *p0.y = *p.y; + GCS::Point p0; + GCS::Point& p = pos == PointPos::start ? Points[Geoms[geoId].startPointId] + : Points[Geoms[geoId].endPointId]; + p0.x = &MoveParameters.emplace_back(*p.x); + p0.y = &MoveParameters.emplace_back(*p.y); GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); } + else if (pos == PointPos::none || pos == PointPos::mid) { + GCS::Point p1, p2; + GCS::Line& l = Lines[Geoms[geoId].index]; + p1.x = &MoveParameters.emplace_back(*l.p1.x); + p1.y = &MoveParameters.emplace_back(*l.p1.y); + p2.x = &MoveParameters.emplace_back(*l.p2.x); + p2.y = &MoveParameters.emplace_back(*l.p2.y); + GCSsys.addConstraintP2PCoincident(p1, l.p1, GCS::DefaultTemporaryConstraint); + GCSsys.addConstraintP2PCoincident(p2, l.p2, GCS::DefaultTemporaryConstraint); + } + } + else if (Geoms[geoId].type == Circle) { + GCS::Point& center = Points[Geoms[geoId].midPointId]; + GCS::Point p0, p1; + if (pos == PointPos::mid) { + p0.x = &MoveParameters.emplace_back(*center.x); + p0.y = &MoveParameters.emplace_back(*center.y); + GCSsys.addConstraintP2PCoincident(p0, center, GCS::DefaultTemporaryConstraint); + } else if (pos == PointPos::none) { - GCS::Arc& a = Arcs[Geoms[geoId].index]; - p0.x = &MoveParameters[0]; - p0.y = &MoveParameters[1]; - *p0.x = *center.x; - *p0.y = *center.y + *a.rad; - GCSsys.addConstraintPointOnArc(p0, a, GCS::DefaultTemporaryConstraint); + // bool pole = GeometryFacade::isInternalType(Geoms[geoId].geo, + // InternalType::BSplineControlPoint); + GCS::Circle& c = Circles[Geoms[geoId].index]; + p0.x = &MoveParameters.emplace_back(*center.x); + p0.y = &MoveParameters.emplace_back(*center.y + *c.rad); + GCSsys.addConstraintPointOnCircle(p0, c, GCS::DefaultTemporaryConstraint); + p1.x = &MoveParameters.emplace_back(*center.x); + p1.y = &MoveParameters.emplace_back(*center.y); + int i = + GCSsys.addConstraintP2PCoincident(p1, center, GCS::DefaultTemporaryConstraint); + GCSsys.rescaleConstraint(i - 1, 0.01); + GCSsys.rescaleConstraint(i, 0.01); + } + } + else if (Geoms[geoId].type == Ellipse) { + if (pos == PointPos::mid || pos == PointPos::none) { + GCS::Point& center = Points[Geoms[geoId].midPointId]; + GCS::Point p0; + p0.x = &MoveParameters.emplace_back(*center.x); + p0.y = &MoveParameters.emplace_back(*center.y); + GCSsys.addConstraintP2PCoincident(p0, center, GCS::DefaultTemporaryConstraint); + } + } + else if (Geoms[geoId].type == ArcOfEllipse) { + + GCS::Point& center = Points[Geoms[geoId].midPointId]; + GCS::Point p0, p1; + if (pos == PointPos::mid || pos == PointPos::none) { + p0.x = &MoveParameters.emplace_back(*center.x); + p0.y = &MoveParameters.emplace_back(*center.y); + GCSsys.addConstraintP2PCoincident(p0, center, GCS::DefaultTemporaryConstraint); + } + else if (pos == PointPos::start || pos == PointPos::end) { + if (pos == PointPos::start || pos == PointPos::end) { + GCS::Point& p = (pos == PointPos::start) ? Points[Geoms[geoId].startPointId] + : Points[Geoms[geoId].endPointId]; + + p0.x = &MoveParameters.emplace_back(*p.x); + p0.y = &MoveParameters.emplace_back(*p.y); + GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); + } + + p1.x = &MoveParameters.emplace_back(*center.x); + p1.y = &MoveParameters.emplace_back(*center.y); + + int i = + GCSsys.addConstraintP2PCoincident(p1, center, GCS::DefaultTemporaryConstraint); + GCSsys.rescaleConstraint(i - 1, 0.01); + GCSsys.rescaleConstraint(i, 0.01); + } + } + else if (Geoms[geoId].type == ArcOfHyperbola) { + GCS::Point& center = Points[Geoms[geoId].midPointId]; + GCS::Point p0, p1; + if (pos == PointPos::mid || pos == PointPos::none) { + p0.x = &MoveParameters.emplace_back(*center.x); + p0.y = &MoveParameters.emplace_back(*center.y); + GCSsys.addConstraintP2PCoincident(p0, center, GCS::DefaultTemporaryConstraint); + } + else if (pos == PointPos::start || pos == PointPos::end) { + GCS::Point& p = (pos == PointPos::start) ? Points[Geoms[geoId].startPointId] + : Points[Geoms[geoId].endPointId]; + p0.x = &MoveParameters.emplace_back(*p.x); + p0.y = &MoveParameters.emplace_back(*p.y); + GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); + p1.x = &MoveParameters.emplace_back(*center.x); + p1.y = &MoveParameters.emplace_back(*center.y); + int i = + GCSsys.addConstraintP2PCoincident(p1, center, GCS::DefaultTemporaryConstraint); + GCSsys.rescaleConstraint(i - 1, 0.01); + GCSsys.rescaleConstraint(i, 0.01); + } + } + else if (Geoms[geoId].type == ArcOfParabola) { + GCS::Point& center = Points[Geoms[geoId].midPointId]; + GCS::Point p0, p1; + if (pos == PointPos::mid || pos == PointPos::none) { + p0.x = &MoveParameters.emplace_back(*center.x); + p0.y = &MoveParameters.emplace_back(*center.y); + GCSsys.addConstraintP2PCoincident(p0, center, GCS::DefaultTemporaryConstraint); + } + else if (pos == PointPos::start || pos == PointPos::end) { + GCS::Point& p = (pos == PointPos::start) ? Points[Geoms[geoId].startPointId] + : Points[Geoms[geoId].endPointId]; + p0.x = &MoveParameters.emplace_back(*p.x); + p0.y = &MoveParameters.emplace_back(*p.y); + GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); + p1.x = &MoveParameters.emplace_back(*center.x); + p1.y = &MoveParameters.emplace_back(*center.y); + int i = + GCSsys.addConstraintP2PCoincident(p1, center, GCS::DefaultTemporaryConstraint); + GCSsys.rescaleConstraint(i - 1, 0.01); + GCSsys.rescaleConstraint(i, 0.01); + } + } + else if (Geoms[geoId].type == BSpline) { + if (pos == PointPos::start || pos == PointPos::end) { + GCS::Point p0; + GCS::Point& p = pos == PointPos::start ? Points[Geoms[geoId].startPointId] + : Points[Geoms[geoId].endPointId]; + p0.x = &MoveParameters.emplace_back(*p.x); + p0.y = &MoveParameters.emplace_back(*p.y); + GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); + } + else if (pos == PointPos::none || pos == PointPos::mid) { + GCS::BSpline& bsp = BSplines[Geoms[geoId].index]; + for (auto pole : bsp.poles) { + GCS::Point p1; + p1.x = &MoveParameters.emplace_back(*pole.x); + p1.y = &MoveParameters.emplace_back(*pole.y); + GCSsys.addConstraintP2PCoincident(p1, pole, GCS::DefaultTemporaryConstraint); + } + } + } + else if (Geoms[geoId].type == Arc) { + GCS::Point& center = Points[Geoms[geoId].midPointId]; + GCS::Point p0, p1; + if (pos == PointPos::mid) { + p0.x = &MoveParameters.emplace_back(*center.x); + p0.y = &MoveParameters.emplace_back(*center.y); + GCSsys.addConstraintP2PCoincident(p0, center, GCS::DefaultTemporaryConstraint); + } + else if (pos == PointPos::none && geoEltIds.size() > 1) { + // When group dragging, arcs should move without modification. + GCS::Point p2; + GCS::Point& sp = Points[Geoms[geoId].startPointId]; + GCS::Point& ep = Points[Geoms[geoId].endPointId]; + p0.x = &MoveParameters.emplace_back(*sp.x); + p0.y = &MoveParameters.emplace_back(*sp.y); + GCSsys.addConstraintP2PCoincident(p0, sp, GCS::DefaultTemporaryConstraint); + + p2.x = &MoveParameters.emplace_back(*ep.x); + p2.y = &MoveParameters.emplace_back(*ep.y); + GCSsys.addConstraintP2PCoincident(p2, ep, GCS::DefaultTemporaryConstraint); + + p1.x = &MoveParameters.emplace_back(*center.x); + p1.y = &MoveParameters.emplace_back(*center.y); + int i = + GCSsys.addConstraintP2PCoincident(p1, center, GCS::DefaultTemporaryConstraint); + GCSsys.rescaleConstraint(i - 2, 0.01); + GCSsys.rescaleConstraint(i - 1, 0.01); + GCSsys.rescaleConstraint(i, 0.01); + } + else if (pos == PointPos::start || pos == PointPos::end || pos == PointPos::none) { + if (pos == PointPos::start || pos == PointPos::end) { + GCS::Point& p = (pos == PointPos::start) ? Points[Geoms[geoId].startPointId] + : Points[Geoms[geoId].endPointId]; + p0.x = &MoveParameters.emplace_back(*p.x); + p0.y = &MoveParameters.emplace_back(*p.y); + GCSsys.addConstraintP2PCoincident(p0, p, GCS::DefaultTemporaryConstraint); + } + else if (pos == PointPos::none) { + GCS::Arc& a = Arcs[Geoms[geoId].index]; + p0.x = &MoveParameters.emplace_back(*center.x); + p0.y = &MoveParameters.emplace_back(*center.y + *a.rad); + GCSsys.addConstraintPointOnArc(p0, a, GCS::DefaultTemporaryConstraint); + } + + p1.x = &MoveParameters.emplace_back(*center.x); + p1.y = &MoveParameters.emplace_back(*center.y); + int i = + GCSsys.addConstraintP2PCoincident(p1, center, GCS::DefaultTemporaryConstraint); + GCSsys.rescaleConstraint(i - 1, 0.01); + GCSsys.rescaleConstraint(i, 0.01); } - p1.x = &MoveParameters[2]; - p1.y = &MoveParameters[3]; - *p1.x = *center.x; - *p1.y = *center.y; - int i = GCSsys.addConstraintP2PCoincident(p1, center, GCS::DefaultTemporaryConstraint); - GCSsys.rescaleConstraint(i - 1, 0.01); - GCSsys.rescaleConstraint(i, 0.01); } } + InitParameters = MoveParameters; GCSsys.initSolution(); isInitMove = true; + return 0; } +int Sketch::initMove(int geoId, PointPos pos, bool fine) +{ + std::vector geoEltIds = {GeoElementId(geoId, pos)}; + return initMove(geoEltIds, fine); +} + void Sketch::resetInitMove() { isInitMove = false; @@ -5140,17 +5093,17 @@ int Sketch::initBSplinePieceMove(int geoId, return 0; } -int Sketch::movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative) +int Sketch::moveGeometries(std::vector geoEltIds, + Base::Vector3d toPoint, + bool relative) { - geoId = checkGeoId(geoId); - - // don't try to move sketches that contain conflicting constraints if (hasConflicts()) { + // don't try to move sketches that contain conflicting constraints return -1; } if (!isInitMove) { - initMove(geoId, pos); + initMove(geoEltIds); initToPoint = toPoint; moveStep = 0; } @@ -5162,7 +5115,7 @@ int Sketch::movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool rela else { // I am getting too far away from the original solution so reinit the solution if ((toPoint - initToPoint).Length() > 20 * moveStep) { - initMove(geoId, pos); + initMove(geoEltIds); initToPoint = toPoint; } } @@ -5170,92 +5123,82 @@ int Sketch::movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool rela } if (relative) { - for (int i = 0; i < int(MoveParameters.size() - 1); i += 2) { + for (size_t i = 0; i < MoveParameters.size() - 1; i += 2) { MoveParameters[i] = InitParameters[i] + toPoint.x; MoveParameters[i + 1] = InitParameters[i + 1] + toPoint.y; } } - else if (Geoms[geoId].type == Point) { - if (pos == PointPos::start) { - MoveParameters[0] = toPoint.x; - MoveParameters[1] = toPoint.y; - } - } - else if (Geoms[geoId].type == Line) { - if (pos == PointPos::start || pos == PointPos::end) { - MoveParameters[0] = toPoint.x; - MoveParameters[1] = toPoint.y; - } - else if (pos == PointPos::none || pos == PointPos::mid) { - double dx = (InitParameters[2] - InitParameters[0]) / 2; - double dy = (InitParameters[3] - InitParameters[1]) / 2; - MoveParameters[0] = toPoint.x - dx; - MoveParameters[1] = toPoint.y - dy; - MoveParameters[2] = toPoint.x + dx; - MoveParameters[3] = toPoint.y + dy; - } - } - else if (Geoms[geoId].type == Circle) { - if (pos == PointPos::mid || pos == PointPos::none) { - MoveParameters[0] = toPoint.x; - MoveParameters[1] = toPoint.y; - } - } - else if (Geoms[geoId].type == Arc) { - if (pos == PointPos::start || pos == PointPos::end || pos == PointPos::mid - || pos == PointPos::none) { - MoveParameters[0] = toPoint.x; - MoveParameters[1] = toPoint.y; - } - } - else if (Geoms[geoId].type == Ellipse) { - if (pos == PointPos::mid || pos == PointPos::none) { - MoveParameters[0] = toPoint.x; - MoveParameters[1] = toPoint.y; - } - } - else if (Geoms[geoId].type == ArcOfEllipse) { - if (pos == PointPos::start || pos == PointPos::end || pos == PointPos::mid - || pos == PointPos::none) { - MoveParameters[0] = toPoint.x; - MoveParameters[1] = toPoint.y; - } - } - else if (Geoms[geoId].type == ArcOfHyperbola) { - if (pos == PointPos::start || pos == PointPos::end || pos == PointPos::mid - || pos == PointPos::none) { - MoveParameters[0] = toPoint.x; - MoveParameters[1] = toPoint.y; - } - } - else if (Geoms[geoId].type == ArcOfParabola) { - if (pos == PointPos::start || pos == PointPos::end || pos == PointPos::mid - || pos == PointPos::none) { - MoveParameters[0] = toPoint.x; - MoveParameters[1] = toPoint.y; - } - } - else if (Geoms[geoId].type == BSpline) { - if (pos == PointPos::start || pos == PointPos::end) { - MoveParameters[0] = toPoint.x; - MoveParameters[1] = toPoint.y; - } - else if (pos == PointPos::none || pos == PointPos::mid) { - GCS::BSpline& bsp = BSplines[Geoms[geoId].index]; - - double cx = 0, cy = 0; // geometric center - for (int i = 0; i < int(InitParameters.size() - 1); i += 2) { - cx += InitParameters[i]; - cy += InitParameters[i + 1]; + else { + size_t i = 0; + for (auto& pair : geoEltIds) { + if (i >= MoveParameters.size()) { + break; } + int geoId = checkGeoId(pair.GeoId); + Sketcher::PointPos pos = pair.Pos; - cx /= bsp.poles.size(); - cy /= bsp.poles.size(); + if (Geoms[geoId].type == Point) { + if (pos == PointPos::start) { + MoveParameters[i] = toPoint.x; + MoveParameters[i + 1] = toPoint.y; + i += 2; + } + } + else if (Geoms[geoId].type == Line) { + if (pos == PointPos::start || pos == PointPos::end) { + MoveParameters[i] = toPoint.x; + MoveParameters[i + 1] = toPoint.y; + i += 2; + } + else if (pos == PointPos::none || pos == PointPos::mid) { + double dx = (InitParameters[i + 2] - InitParameters[i]) * 0.5; + double dy = (InitParameters[i + 3] - InitParameters[i + 1]) * 0.5; + MoveParameters[i] = toPoint.x - dx; + MoveParameters[i + 1] = toPoint.y - dy; + MoveParameters[i + 2] = toPoint.x + dx; + MoveParameters[i + 3] = toPoint.y + dy; + i += 4; + } + } + else if (Geoms[geoId].type == Circle || Geoms[geoId].type == Ellipse) { + if (pos == PointPos::mid || pos == PointPos::none) { + MoveParameters[i] = toPoint.x; + MoveParameters[i + 1] = toPoint.y; + i += 2; + } + } + else if (Geoms[geoId].type == Arc || Geoms[geoId].type == ArcOfEllipse + || Geoms[geoId].type == ArcOfHyperbola || Geoms[geoId].type == ArcOfParabola) { + MoveParameters[i] = toPoint.x; + MoveParameters[i + 1] = toPoint.y; + i += 2; + } + else if (Geoms[geoId].type == BSpline) { + if (pos == PointPos::start || pos == PointPos::end) { + MoveParameters[i] = toPoint.x; + MoveParameters[i + 1] = toPoint.y; + i += 2; + } + else if (pos == PointPos::none || pos == PointPos::mid) { + GCS::BSpline& bsp = BSplines[Geoms[geoId].index]; - for (int i = 0; i < int(MoveParameters.size() - 1); i += 2) { + double cx = 0, cy = 0; // geometric center + for (size_t j = 0; j < bsp.poles.size() * 2; j += 2) { + cx += InitParameters[i + j]; + cy += InitParameters[i + j + 1]; + j += 2; + } - MoveParameters[i] = toPoint.x + InitParameters[i] - cx; - MoveParameters[i + 1] = toPoint.y + InitParameters[i + 1] - cy; + cx /= bsp.poles.size(); + cy /= bsp.poles.size(); + + for (size_t j = 0; j < bsp.poles.size() * 2; j += 2) { + MoveParameters[i + j] = toPoint.x + InitParameters[i + j] - cx; + MoveParameters[i + j + 1] = toPoint.y + InitParameters[i + j + 1] - cy; + j += 2; + } + i += bsp.poles.size() * 2; + } } } } @@ -5263,6 +5206,12 @@ int Sketch::movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool rela return solve(); } +int Sketch::moveGeometry(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative) +{ + std::vector geoEltIds = {GeoElementId(geoId, pos)}; + return moveGeometries(geoEltIds, toPoint, relative); +} + int Sketch::setDatum(int /*constrId*/, double /*value*/) { return -1; diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index 0ffff0ed26..aef9bb9b08 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -161,6 +161,7 @@ public: /** initializes a point (or curve) drag by setting the current * sketch status as a reference */ + int initMove(std::vector geoEltIds, bool fine = true); int initMove(int geoId, PointPos pos, bool fine = true); /** Initializes a B-spline piece drag by setting the current @@ -184,7 +185,10 @@ public: * a condition for satisfying the new point location! * The relative flag permits moving relatively to the current position */ - int movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative = false); + int moveGeometries(std::vector geoEltIds, + Base::Vector3d toPoint, + bool relative = false); + int moveGeometry(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative = false); /** * Sets whether the initial solution should be recalculated while dragging after a certain diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 491774b9e3..2423e7019c 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -1340,9 +1340,10 @@ int SketchObject::diagnoseAdditionalConstraints( return lastDoF; } -int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toPoint, bool relative, +int SketchObject::moveGeometries(std::vector geoEltIds, const Base::Vector3d& toPoint, bool relative, bool updateGeoBeforeMoving) { + // no need to check input data validity as this is an sketchobject managed operation. Base::StateLocker lock(managedoperation, true); @@ -1369,7 +1370,7 @@ int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toP return -1; // move the point and solve - lastSolverStatus = solvedSketch.movePoint(GeoId, PosId, toPoint, relative); + lastSolverStatus = solvedSketch.moveGeometries(geoEltIds, toPoint, relative); // moving the point can not result in a conflict that we did not have // or a redundancy that we did not have before, or a change of DoF @@ -1378,10 +1379,10 @@ int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toP std::vector geomlist = solvedSketch.extractGeometry(); Geometry.setValues(geomlist); // Constraints.acceptGeometry(getCompleteGeometry()); - for (std::vector::iterator it = geomlist.begin(); it != geomlist.end(); - ++it) { - if (*it) - delete *it; + for (auto* geo : geomlist) { + if (geo){ + delete geo; + } } } @@ -1390,6 +1391,13 @@ int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toP return lastSolverStatus; } +int SketchObject::moveGeometry(int geoId, PointPos pos, const Base::Vector3d& toPoint, bool relative, + bool updateGeoBeforeMoving) +{ + std::vector geoEltIds = { GeoElementId(geoId, pos) }; + return moveGeometries(geoEltIds, toPoint, relative, updateGeoBeforeMoving); +} + template <> Base::Vector3d SketchObject::getPointForGeometry<>(const Part::GeomPoint *geomPoint, PointPos PosId) { @@ -2777,14 +2785,14 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1, if (dist1.Length() < dist2.Length()) { filletPosId1 = PointPos::start; filletPosId2 = PointPos::end; - movePoint(GeoId1, PosId1, p1, false, true); - movePoint(GeoId2, PosId2, p2, false, true); + moveGeometry(GeoId1, PosId1, p1, false, true); + moveGeometry(GeoId2, PosId2, p2, false, true); } else { filletPosId1 = PointPos::end; filletPosId2 = PointPos::start; - movePoint(GeoId1, PosId1, p2, false, true); - movePoint(GeoId2, PosId2, p1, false, true); + moveGeometry(GeoId1, PosId1, p2, false, true); + moveGeometry(GeoId2, PosId2, p1, false, true); } auto tangent1 = std::make_unique(); @@ -3272,14 +3280,14 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1, if (dist1 < dist2) { filletPosId1 = PointPos::start; filletPosId2 = PointPos::end; - movePoint(GeoId1, PosId1, p1, false, true); - movePoint(GeoId2, PosId2, p2, false, true); + moveGeometry(GeoId1, PosId1, p1, false, true); + moveGeometry(GeoId2, PosId2, p2, false, true); } else { filletPosId1 = PointPos::end; filletPosId2 = PointPos::start; - movePoint(GeoId1, PosId1, p2, false, true); - movePoint(GeoId2, PosId2, p1, false, true); + moveGeometry(GeoId1, PosId1, p2, false, true); + moveGeometry(GeoId2, PosId2, p1, false, true); } auto* tangent1 = new Sketcher::Constraint(); @@ -3377,7 +3385,7 @@ int SketchObject::extend(int GeoId, double increment, PointPos endpoint) newPoint.Normalize(); newPoint.Scale(scaleFactor, scaleFactor, scaleFactor); newPoint = newPoint + endVec; - retcode = movePoint(GeoId, Sketcher::PointPos::start, newPoint, false, true); + retcode = moveGeometry(GeoId, Sketcher::PointPos::start, newPoint, false, true); } else if (endpoint == PointPos::end) { Base::Vector3d newPoint = endVec - startVec; @@ -3385,7 +3393,7 @@ int SketchObject::extend(int GeoId, double increment, PointPos endpoint) newPoint.Normalize(); newPoint.Scale(scaleFactor, scaleFactor, scaleFactor); newPoint = newPoint + startVec; - retcode = movePoint(GeoId, Sketcher::PointPos::end, newPoint, false, true); + retcode = moveGeometry(GeoId, Sketcher::PointPos::end, newPoint, false, true); } } else if (geom->is()) { diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index 50dfc85f63..1b6239691f 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -352,11 +352,15 @@ public: /// toggle the driving status of this constraint int toggleVirtualSpace(int ConstrId); /// move this point to a new location and solve - int movePoint(int GeoId, - PointPos PosId, - const Base::Vector3d& toPoint, - bool relative = false, - bool updateGeoBeforeMoving = false); + int moveGeometries(std::vector geoEltIds, + const Base::Vector3d& toPoint, + bool relative = false, + bool updateGeoBeforeMoving = false); + int moveGeometry(int GeoId, + PointPos PosId, + const Base::Vector3d& toPoint, + bool relative = false, + bool updateGeoBeforeMoving = false); /// retrieves the coordinates of a point static Base::Vector3d getPoint(const Part::Geometry* geo, PointPos PosId); Base::Vector3d getPoint(int GeoId, PointPos PosId) const; @@ -689,6 +693,8 @@ public: /* Solver exposed interface */ } /// Forwards a request for a temporary initMove to the solver using the current sketch state as /// a reference (enables dragging) + + inline int initTemporaryMove(std::vector moved, bool fine = true); inline int initTemporaryMove(int geoId, PointPos pos, bool fine = true); /// Forwards a request for a temporary initBSplinePieceMove to the solver using the current /// sketch state as a reference (enables dragging) @@ -700,8 +706,11 @@ public: /* Solver exposed interface */ * state as a reference (enables dragging). NOTE: A temporary move operation must always be * preceded by a initTemporaryMove() operation. */ + inline int moveGeometriesTemporary(std::vector moved, + Base::Vector3d toPoint, + bool relative = false); inline int - moveTemporaryPoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative = false); + moveGeometryTemporary(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative = false); /// forwards a request to update an extension of a geometry of the solver to the solver. inline void updateSolverExtension(int geoId, std::unique_ptr&& ext) { @@ -992,7 +1001,7 @@ private: /** this internal flag indicate that an operation modifying the geometry, but not the DoF of the sketch took place (e.g. toggle construction), so if next action is a movement of a point - (movePoint), the geometry must be updated first. + (moveGeometry), the geometry must be updated first. */ bool solverNeedsUpdate; @@ -1063,16 +1072,19 @@ private: mutable std::map internalElementMap; }; -inline int SketchObject::initTemporaryMove(int geoId, PointPos pos, bool fine /*=true*/) +inline int SketchObject::initTemporaryMove(std::vector moved, bool fine /*=true*/) { - // if a previous operation did not update the geometry (including geometry extensions) - // or constraints (including any deleted pointer, as in renameConstraint) of the solver, - // here we update them before starting a temporary operation. if (solverNeedsUpdate) { solve(); } - return solvedSketch.initMove(geoId, pos, fine); + return solvedSketch.initMove(moved, fine); +} + +inline int SketchObject::initTemporaryMove(int geoId, PointPos pos, bool fine /*=true*/) +{ + std::vector moved = {GeoElementId(geoId, pos)}; + return initTemporaryMove(moved, fine); } inline int SketchObject::initTemporaryBSplinePieceMove(int geoId, @@ -1090,12 +1102,19 @@ inline int SketchObject::initTemporaryBSplinePieceMove(int geoId, return solvedSketch.initBSplinePieceMove(geoId, pos, firstPoint, fine); } -inline int SketchObject::moveTemporaryPoint(int geoId, - PointPos pos, - Base::Vector3d toPoint, - bool relative /*=false*/) +inline int SketchObject::moveGeometriesTemporary(std::vector geoEltIds, + Base::Vector3d toPoint, + bool relative /*=false*/) { - return solvedSketch.movePoint(geoId, pos, toPoint, relative); + return solvedSketch.moveGeometries(geoEltIds, toPoint, relative); +} +inline int SketchObject::moveGeometryTemporary(int geoId, + PointPos pos, + Base::Vector3d toPoint, + bool relative /*=false*/) +{ + std::vector moved = {GeoElementId(geoId, pos)}; + return moveGeometriesTemporary(moved, toPoint, relative); } diff --git a/src/Mod/Sketcher/App/SketchObjectPy.xml b/src/Mod/Sketcher/App/SketchObjectPy.xml index b47a995cbc..d9d5834b9b 100644 --- a/src/Mod/Sketcher/App/SketchObjectPy.xml +++ b/src/Mod/Sketcher/App/SketchObjectPy.xml @@ -513,10 +513,10 @@ setLabelDistance(constraintIndex:int, value:float) - + - movePoint(GeoIndex,PointPos,Vector,[relative]) - move a given point (or curve) + moveGeometry(GeoIndex,PointPos,Vector,[relative]) - move a given point (or curve) to another location. It moves the specified point (or curve) to the given location by adding some temporary weak constraints and solve the sketch. @@ -528,6 +528,22 @@ setLabelDistance(constraintIndex:int, value:float) + + + + moveGeometries(Geos,Vector,[relative]) - move given points and curves + to another location. + It moves the specified points and curves to the given location by adding some + temporary weak constraints and solve the sketch. + This method is mostly used to allow the user to drag some portions of the sketch + in real time by e.g. the mouse and it works only for underconstrained portions of + the sketch. + The argument 'relative', if present, states if the new location is given + relatively to the current one. For group dragging this is enforced. + Geos is a vector of pairs of geoId and posId. + + + diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index 67550b5cb5..072e389e66 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -1167,7 +1167,59 @@ PyObject* SketchObjectPy::setLabelDistance(PyObject* args) Py_Return; } -PyObject* SketchObjectPy::movePoint(PyObject* args) +PyObject* SketchObjectPy::moveGeometries(PyObject* args) +{ + PyObject* pyList; + PyObject* pcObj; + int relative = 0; + + // Parse arguments: list of pairs, Base::VectorPy, optional relative flag + if (!PyArg_ParseTuple(args, + "O!O!|i", + &PyList_Type, + &pyList, // List of pairs (geoId, pointPos) + &(Base::VectorPy::Type), + &pcObj, // Target vector + &relative)) { // Optional relative flag + return nullptr; + } + + // Convert Python list to std::vector + std::vector geoEltIds; + Py_ssize_t listSize = PyList_Size(pyList); + + for (Py_ssize_t i = 0; i < listSize; ++i) { + PyObject* pyPair = PyList_GetItem(pyList, i); // Borrowed reference + + if (!PyTuple_Check(pyPair) || PyTuple_Size(pyPair) != 2) { + PyErr_SetString(PyExc_ValueError, "List must contain pairs (geoId, pointPos)."); + return nullptr; + } + + int geoId = PyLong_AsLong(PyTuple_GetItem(pyPair, 0)); + int pointPos = PyLong_AsLong(PyTuple_GetItem(pyPair, 1)); + + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "Invalid geoId or pointPos in the list."); + return nullptr; + } + + geoEltIds.emplace_back(GeoElementId(geoId, static_cast(pointPos))); + } + + // Convert Python vector to Base::Vector3d + Base::Vector3d v1 = static_cast(pcObj)->value(); + + // Call the C++ method + if (this->getSketchObjectPtr()->moveGeometries(geoEltIds, v1, (relative > 0))) { + PyErr_SetString(PyExc_ValueError, "Failed to move geometries."); + return nullptr; + } + + Py_RETURN_NONE; +} + +PyObject* SketchObjectPy::moveGeometry(PyObject* args) { PyObject* pcObj; int GeoId, PointType; @@ -1185,10 +1237,10 @@ PyObject* SketchObjectPy::movePoint(PyObject* args) Base::Vector3d v1 = static_cast(pcObj)->value(); - if (this->getSketchObjectPtr()->movePoint(GeoId, - static_cast(PointType), - v1, - (relative > 0))) { + if (this->getSketchObjectPtr()->moveGeometry(GeoId, + static_cast(PointType), + v1, + (relative > 0))) { std::stringstream str; str << "Not able to move point with the id and type: (" << GeoId << ", " << PointType << ")"; diff --git a/src/Mod/Sketcher/App/SketchPy.xml b/src/Mod/Sketcher/App/SketchPy.xml index bc4599e111..7285d7951e 100644 --- a/src/Mod/Sketcher/App/SketchPy.xml +++ b/src/Mod/Sketcher/App/SketchPy.xml @@ -35,10 +35,10 @@ clear the sketch - + - movePoint(GeoIndex,PointPos,Vector,[relative]) - move a given point (or curve) + moveGeometry(GeoIndex,PointPos,Vector,[relative]) - move a given point (or curve) to another location. It moves the specified point (or curve) to the given location by adding some temporary weak constraints and solve the sketch. diff --git a/src/Mod/Sketcher/App/SketchPyImp.cpp b/src/Mod/Sketcher/App/SketchPyImp.cpp index 5d25ea726b..98d85b5e45 100644 --- a/src/Mod/Sketcher/App/SketchPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchPyImp.cpp @@ -151,7 +151,7 @@ PyObject* SketchPy::clear(PyObject* args) Py_RETURN_NONE; } -PyObject* SketchPy::movePoint(PyObject* args) +PyObject* SketchPy::moveGeometry(PyObject* args) { int index1, index2; PyObject* pcObj; @@ -168,10 +168,10 @@ PyObject* SketchPy::movePoint(PyObject* args) Base::Vector3d* toPoint = static_cast(pcObj)->getVectorPtr(); return Py::new_reference_to( - Py::Long(getSketchPtr()->movePoint(index1, - static_cast(index2), - *toPoint, - (relative > 0)))); + Py::Long(getSketchPtr()->moveGeometry(index1, + static_cast(index2), + *toPoint, + (relative > 0)))); } // +++ attributes implementer ++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index e2f814002b..edaa9bec7e 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -2502,7 +2502,7 @@ protected: Base::Vector3d p2 = line->getEndPoint(); if (fabs(p1.y - p2.y) < Precision::Confusion()) { // effectively vertical p2 = p1 + (p2 - p1).Length() * Base::Vector3d(0.0, 1.0, 0.0); - Gui::cmdAppObjectArgs(Obj, "movePoint(%d,2,App.Vector(%f, %f, 0),0) ", GeoId1, p2.x, p2.y); + Gui::cmdAppObjectArgs(Obj, "moveGeometry(%d,2,App.Vector(%f, %f, 0),0) ", GeoId1, p2.x, p2.y); } Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Vertical',%d)) ", GeoId1); } @@ -2530,7 +2530,7 @@ protected: Base::Vector3d p2 = line->getEndPoint(); if (fabs(p1.x - p2.x) < Precision::Confusion()) { // effectively vertical p2 = p1 + (p2 - p1).Length() * Base::Vector3d(1.0, 0.0, 0.0); - Gui::cmdAppObjectArgs(Obj, "movePoint(%d,2,App.Vector(%f, %f, 0),0) ", GeoId1, p2.x, p2.y); + Gui::cmdAppObjectArgs(Obj, "moveGeometry(%d,2,App.Vector(%f, %f, 0),0) ", GeoId1, p2.x, p2.y); } Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Horizontal',%d)) ", GeoId1); } diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index aa7fdb31bd..8ea22eb7ca 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -715,8 +715,8 @@ void ViewProviderSketch::ensureFocus() void ViewProviderSketch::preselectAtPoint(Base::Vector2d point) { if (Mode != STATUS_SELECT_Point && Mode != STATUS_SELECT_Edge - && Mode != STATUS_SELECT_Constraint && Mode != STATUS_SKETCH_DragPoint - && Mode != STATUS_SKETCH_DragCurve && Mode != STATUS_SKETCH_DragConstraint + && Mode != STATUS_SELECT_Constraint && Mode != STATUS_SKETCH_Drag + && Mode != STATUS_SKETCH_DragConstraint && Mode != STATUS_SKETCH_UseRubberBand) { Gui::MDIView* mdi = this->getActiveView(); @@ -766,24 +766,9 @@ bool ViewProviderSketch::keyPressed(bool pressed, int key) } return true; } - if (isInEditMode() && drag.isDragCurveValid()) { + if (isInEditMode() && !drag.Dragged.empty()) { if (!pressed) { - getSketchObject()->movePoint( - drag.DragCurve, Sketcher::PointPos::none, Base::Vector3d(0, 0, 0), true); - drag.DragCurve = Drag::InvalidCurve; - resetPositionText(); - Mode = STATUS_NONE; - } - return true; - } - if (isInEditMode() && drag.isDragPointValid()) { - if (!pressed) { - int GeoId; - Sketcher::PointPos PosId; - getSketchObject()->getGeoVertexIndex(drag.DragPoint, GeoId, PosId); - getSketchObject()->movePoint(GeoId, PosId, Base::Vector3d(0, 0, 0), true); - drag.DragPoint = Drag::InvalidPoint; - resetPositionText(); + commitDragMove(drag.xInit, drag.yInit); Mode = STATUS_NONE; } return true; @@ -1053,111 +1038,8 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe } Mode = STATUS_NONE; return true; - case STATUS_SKETCH_DragPoint: - if (drag.isDragPointValid()) { - int GeoId; - Sketcher::PointPos PosId; - - getSketchObject()->getGeoVertexIndex(drag.DragPoint, GeoId, PosId); - - if (GeoId != Sketcher::GeoEnum::GeoUndef - && PosId != Sketcher::PointPos::none) { - getDocument()->openCommand(QT_TRANSLATE_NOOP("Command", "Drag Point")); - try { - Gui::cmdAppObjectArgs(getObject(), - "movePoint(%d,%d,App.Vector(%f,%f,0),%d)", - GeoId, - static_cast(PosId), - x - drag.xInit, - y - drag.yInit, - 0); - - getDocument()->commitCommand(); - - tryAutoRecomputeIfNotSolve(getSketchObject()); - } - catch (const Base::Exception& e) { - getDocument()->abortCommand(); - Base::Console().DeveloperError( - "ViewProviderSketch", "Drag point: %s\n", e.what()); - } - } - setPreselectPoint(drag.DragPoint); - drag.DragPoint = Drag::InvalidPoint; - } - resetPositionText(); - Mode = STATUS_NONE; - return true; - case STATUS_SKETCH_DragCurve: - if (drag.isDragCurveValid()) { - const Part::Geometry* geo = getSketchObject()->getGeometry(drag.DragCurve); - if (geo->is() - || geo->is() - || geo->is() - || geo->is() - || geo->is() - || geo->is() - || geo->is() - || geo->is()) { - getDocument()->openCommand(QT_TRANSLATE_NOOP("Command", "Drag Curve")); - - auto geo = getSketchObject()->getGeometry(drag.DragCurve); - auto gf = GeometryFacade::getFacade(geo); - - Base::Vector3d vec(x - drag.xInit, y - drag.yInit, 0); - - // BSpline weights have a radius corresponding to the weight value - // However, in order for them proportional to the B-Spline size, - // the scenograph has a size scalefactor times the weight - // This code normalizes the information sent to the solver. - if (gf->getInternalType() == InternalType::BSplineControlPoint) { - auto circle = static_cast(geo); - Base::Vector3d center = circle->getCenter(); - - Base::Vector3d dir = vec - center; - - double scalefactor = 1.0; - - if (circle->hasExtension( - SketcherGui::ViewProviderSketchGeometryExtension:: - getClassTypeId())) { - auto vpext = std::static_pointer_cast< - const SketcherGui::ViewProviderSketchGeometryExtension>( - circle - ->getExtension( - SketcherGui::ViewProviderSketchGeometryExtension:: - getClassTypeId()) - .lock()); - - scalefactor = vpext->getRepresentationFactor(); - } - - vec = center + dir / scalefactor; - } - - try { - Gui::cmdAppObjectArgs(getObject(), - "movePoint(%d,%d,App.Vector(%f,%f,0),%d)", - drag.DragCurve, - static_cast(Sketcher::PointPos::none), - vec.x, - vec.y, - drag.relative ? 1 : 0); - - getDocument()->commitCommand(); - - tryAutoRecomputeIfNotSolve(getSketchObject()); - } - catch (const Base::Exception& e) { - getDocument()->abortCommand(); - Base::Console().DeveloperError( - "ViewProviderSketch", "Drag curve: %s\n", e.what()); - } - } - preselection.PreselectCurve = drag.DragCurve; - drag.DragCurve = Drag::InvalidCurve; - } - resetPositionText(); + case STATUS_SKETCH_Drag: + commitDragMove(x, y); Mode = STATUS_NONE; return true; case STATUS_SKETCH_DragConstraint: @@ -1313,8 +1195,7 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe generateContextMenu(); return true; } - case STATUS_SKETCH_DragPoint: - case STATUS_SKETCH_DragCurve: + case STATUS_SKETCH_Drag: case STATUS_SKETCH_DragConstraint: case STATUS_SKETCH_StartRubberBand: case STATUS_SKETCH_UseRubberBand: @@ -1487,9 +1368,8 @@ bool ViewProviderSketch::mouseMove(const SbVec2s& cursorPos, Gui::View3DInventor bool preselectChanged = false; if (Mode != STATUS_SELECT_Point && Mode != STATUS_SELECT_Edge - && Mode != STATUS_SELECT_Constraint && Mode != STATUS_SKETCH_DragPoint - && Mode != STATUS_SKETCH_DragCurve && Mode != STATUS_SKETCH_DragConstraint - && Mode != STATUS_SKETCH_UseRubberBand) { + && Mode != STATUS_SELECT_Constraint && Mode != STATUS_SKETCH_Drag + && Mode != STATUS_SKETCH_DragConstraint && Mode != STATUS_SKETCH_UseRubberBand) { std::unique_ptr Point(this->getPointOnRay(cursorPos, viewer)); @@ -1505,19 +1385,12 @@ bool ViewProviderSketch::mouseMove(const SbVec2s& cursorPos, Gui::View3DInventor } return false; case STATUS_SELECT_Point: - if (!getSolvedSketch().hasConflicts() && preselection.isPreselectPointValid() - && drag.DragPoint != preselection.PreselectPoint) { - Mode = STATUS_SKETCH_DragPoint; - drag.DragPoint = preselection.PreselectPoint; - int GeoId; - Sketcher::PointPos PosId; + if (!getSolvedSketch().hasConflicts() && preselection.isPreselectPointValid()) { + int geoId; + Sketcher::PointPos pos; + getSketchObject()->getGeoVertexIndex(preselection.PreselectPoint, geoId, pos); - getSketchObject()->getGeoVertexIndex(drag.DragPoint, GeoId, PosId); - - if (GeoId != Sketcher::GeoEnum::GeoUndef && PosId != Sketcher::PointPos::none) { - getSketchObject()->initTemporaryMove(GeoId, PosId, false); - drag.resetVector(); - } + initDragging(geoId, pos, viewer); } else { Mode = STATUS_NONE; @@ -1525,107 +1398,11 @@ bool ViewProviderSketch::mouseMove(const SbVec2s& cursorPos, Gui::View3DInventor resetPreselectPoint(); return true; case STATUS_SELECT_Edge: - if (!getSolvedSketch().hasConflicts() && preselection.isPreselectCurveValid() - && drag.DragCurve != preselection.PreselectCurve) { - Mode = STATUS_SKETCH_DragCurve; - drag.DragCurve = preselection.PreselectCurve; - const Part::Geometry* geo = getSketchObject()->getGeometry(drag.DragCurve); + if (!getSolvedSketch().hasConflicts() && preselection.isPreselectCurveValid()) { + int geoId = preselection.PreselectCurve; + Sketcher::PointPos pos = Sketcher::PointPos::none; - // BSpline Control points are edge draggable only if their radius is movable - // This is because dragging gives unwanted cosmetic results due to the scale ratio. - // This is an heuristic as it does not check all indirect routes. - if (GeometryFacade::isInternalType(geo, InternalType::BSplineControlPoint)) { - if (geo->hasExtension(Sketcher::SolverGeometryExtension::getClassTypeId())) { - auto solvext = - std::static_pointer_cast( - geo->getExtension( - Sketcher::SolverGeometryExtension::getClassTypeId()) - .lock()); - - // Edge parameters are Independent, so weight won't move - if (solvext->getEdge() == Sketcher::SolverGeometryExtension::Independent) { - Mode = STATUS_NONE; - return false; - } - - // The B-Spline is constrained to be non-rational (equal weights), moving - // produces a bad effect because OCCT will normalize the values of the - // weights. - auto grp = getSolvedSketch().getDependencyGroup(drag.DragCurve, - Sketcher::PointPos::none); - - int bsplinegeoid = -1; - - std::vector polegeoids; - - for (auto c : getSketchObject()->Constraints.getValues()) { - if (c->Type == Sketcher::InternalAlignment - && c->AlignmentType == BSplineControlPoint - && c->First == drag.DragCurve) { - - bsplinegeoid = c->Second; - break; - } - } - - if (bsplinegeoid == -1) { - Mode = STATUS_NONE; - return false; - } - - for (auto c : getSketchObject()->Constraints.getValues()) { - if (c->Type == Sketcher::InternalAlignment - && c->AlignmentType == BSplineControlPoint - && c->Second == bsplinegeoid) { - - polegeoids.push_back(c->First); - } - } - - bool allingroup = true; - - for (auto polegeoid : polegeoids) { - std::pair thispole = - std::make_pair(polegeoid, Sketcher::PointPos::none); - - if (grp.find(thispole) == grp.end())// not found - allingroup = false; - } - - if (allingroup) {// it is constrained to be non-rational - Mode = STATUS_NONE; - return false; - } - } - } - - if (geo->is() - || geo->is()) { - drag.relative = true; - - // Since the cursor moved from where it was clicked, and this is a relative - // move, calculate the click position and use it as initial point. - SbLine line2; - getProjectingLine(DoubleClick::prvCursorPos, viewer, line2); - getCoordsOnSketchPlane( - line2.getPosition(), line2.getDirection(), drag.xInit, drag.yInit); - snapManager->snap(drag.xInit, drag.yInit); - } - else { - drag.resetVector(); - } - - if (geo->is()) { - getSketchObject()->initTemporaryBSplinePieceMove( - drag.DragCurve, - Sketcher::PointPos::none, - Base::Vector3d(drag.xInit, drag.yInit, 0.0), - false); - } - else { - getSketchObject()->initTemporaryMove( - drag.DragCurve, Sketcher::PointPos::none, false); - } + initDragging(geoId, pos, viewer); } else { Mode = STATUS_NONE; @@ -1639,64 +1416,10 @@ bool ViewProviderSketch::mouseMove(const SbVec2s& cursorPos, Gui::View3DInventor drag.yInit = y; resetPreselectPoint(); return true; - case STATUS_SKETCH_DragPoint: - if (drag.isDragPointValid()) { - // Base::Console().Log("Drag Point:%d\n",edit->DragPoint); - int GeoId; - Sketcher::PointPos PosId; - getSketchObject()->getGeoVertexIndex(drag.DragPoint, GeoId, PosId); - Base::Vector3d vec(x, y, 0); - - if (GeoId != Sketcher::GeoEnum::GeoUndef && PosId != Sketcher::PointPos::none) { - if (getSketchObject()->moveTemporaryPoint(GeoId, PosId, vec, false) == 0) { - setPositionText(Base::Vector2d(x, y)); - draw(true, false); - } - } - } - return true; - case STATUS_SKETCH_DragCurve: - if (drag.isDragCurveValid()) { - auto geo = getSketchObject()->getGeometry(drag.DragCurve); - auto gf = GeometryFacade::getFacade(geo); - - Base::Vector3d vec(x - drag.xInit, y - drag.yInit, 0); - - // BSpline weights have a radius corresponding to the weight value - // However, in order for them proportional to the B-Spline size, - // the scenograph has a size scalefactor times the weight - // This code normalizes the information sent to the solver. - if (gf->getInternalType() == InternalType::BSplineControlPoint) { - auto circle = static_cast(geo); - Base::Vector3d center = circle->getCenter(); - - Base::Vector3d dir = vec - center; - - double scalefactor = 1.0; - - if (circle->hasExtension( - SketcherGui::ViewProviderSketchGeometryExtension::getClassTypeId())) { - auto vpext = std::static_pointer_cast< - const SketcherGui::ViewProviderSketchGeometryExtension>( - circle - ->getExtension(SketcherGui::ViewProviderSketchGeometryExtension:: - getClassTypeId()) - .lock()); - - scalefactor = vpext->getRepresentationFactor(); - } - - vec = center + dir / scalefactor; - } - - if (getSketchObject()->moveTemporaryPoint( - drag.DragCurve, Sketcher::PointPos::none, vec, drag.relative) - == 0) { - setPositionText(Base::Vector2d(x, y)); - draw(true, false); - } - } + case STATUS_SKETCH_Drag: { + doDragStep(x, y); return true; + } case STATUS_SKETCH_DragConstraint: if (!drag.DragConstraintSet.empty()) { auto idset = drag.DragConstraintSet; @@ -1738,6 +1461,291 @@ bool ViewProviderSketch::mouseMove(const SbVec2s& cursorPos, Gui::View3DInventor return false; } +void ViewProviderSketch::initDragging(int geoId, Sketcher::PointPos pos, Gui::View3DInventorViewer* viewer) +{ + if (geoId < 0) { + return; // don't drag externals + } + + drag.reset(); + Mode = STATUS_SKETCH_Drag; + drag.Dragged.push_back(GeoElementId(geoId, pos)); + + // Adding selected geos that should be dragged as well. + for (auto& geoIdi : selection.SelCurvSet) { + if (geoIdi < 0) { + continue; //skip externals + } + + if (geoIdi == geoId) { + // geoId is already added because it was the preselected. + // 2 cases : either the edge was added or a point of it. + // If its a point then we replace it by the edge. + // If it's the edge it's replaced by itself so it's ok. + drag.Dragged[0].Pos = Sketcher::PointPos::none; + } + else { + // For group dragging, we skip the internal geos. + const Part::Geometry* geo = getSketchObject()->getGeometry(geoId); + if (!GeometryFacade::isInternalAligned(geo)) { + drag.Dragged.push_back(GeoElementId(geoIdi)); + } + } + } + for (auto& pointId : selection.SelPointSet) { + int geoIdi; + Sketcher::PointPos posi; + getSketchObject()->getGeoVertexIndex(pointId, geoIdi, posi); + if (geoIdi < 0) { + continue; //skip externals + } + + bool add = true; + for (auto& pair : drag.Dragged) { + int geoIdj = pair.GeoId; + Sketcher::PointPos posj = pair.Pos; + if (geoIdi == geoIdj && (posi == posj || posj == Sketcher::PointPos::none)) { + add = false; + break; + } + } + if (add) { + drag.Dragged.push_back(GeoElementId(geoIdi, posi)); + } + } + + auto setRelative = [&]() { + drag.relative = true; + + // Calculate the click position and use it as the initial point + SbLine line2; + getProjectingLine(DoubleClick::prvCursorPos, viewer, line2); + getCoordsOnSketchPlane( + line2.getPosition(), line2.getDirection(), drag.xInit, drag.yInit); + snapManager->snap(drag.xInit, drag.yInit); + }; + + if (drag.Dragged.size() == 1 && pos == Sketcher::PointPos::none) { + const Part::Geometry* geo = getSketchObject()->getGeometry(geoId); + + // BSpline Control points are edge draggable only if their radius is movable + // This is because dragging gives unwanted cosmetic results due to the scale ratio. + // This is an heuristic as it does not check all indirect routes. + if (GeometryFacade::isInternalType(geo, InternalType::BSplineControlPoint)) { + if (geo->hasExtension(Sketcher::SolverGeometryExtension::getClassTypeId())) { + auto solvext = + std::static_pointer_cast( + geo->getExtension( + Sketcher::SolverGeometryExtension::getClassTypeId()) + .lock()); + + // Edge parameters are Independent, so weight won't move + if (solvext->getEdge() == Sketcher::SolverGeometryExtension::Independent) { + Mode = STATUS_NONE; + return; + } + + // The B-Spline is constrained to be non-rational (equal weights), moving + // produces a bad effect because OCCT will normalize the values of the + // weights. + auto grp = getSolvedSketch().getDependencyGroup(geoId, + Sketcher::PointPos::none); + + int bsplinegeoid = -1; + + std::vector polegeoids; + + for (auto c : getSketchObject()->Constraints.getValues()) { + if (c->Type == Sketcher::InternalAlignment + && c->AlignmentType == BSplineControlPoint + && c->First == geoId) { + + bsplinegeoid = c->Second; + break; + } + } + + if (bsplinegeoid == -1) { + Mode = STATUS_NONE; + return; + } + + for (auto c : getSketchObject()->Constraints.getValues()) { + if (c->Type == Sketcher::InternalAlignment + && c->AlignmentType == BSplineControlPoint + && c->Second == bsplinegeoid) { + + polegeoids.push_back(c->First); + } + } + + bool allingroup = true; + + for (auto polegeoid : polegeoids) { + std::pair thispole = + std::make_pair(polegeoid, Sketcher::PointPos::none); + + if (grp.find(thispole) == grp.end())// not found + allingroup = false; + } + + if (allingroup) {// it is constrained to be non-rational + Mode = STATUS_NONE; + return; + } + } + } + + if (geo->is() || geo->is()) { + setRelative(); + } + + if (geo->is()) { + getSketchObject()->initTemporaryBSplinePieceMove( + geoId, + Sketcher::PointPos::none, + Base::Vector3d(drag.xInit, drag.yInit, 0.0), + false); + return; + } + } + else if (drag.Dragged.size() > 1) { + setRelative(); + } + + getSketchObject()->initTemporaryMove(drag.Dragged, false); +} + +void ViewProviderSketch::doDragStep(double x, double y) +{ + Base::Vector3d vec(x - drag.xInit, y - drag.yInit, 0); + + if (drag.Dragged.size() == 1) { + // special single bspline point handling. + Sketcher::PointPos PosId = drag.Dragged[0].Pos; + + if (PosId == Sketcher::PointPos::none) { + int GeoId = drag.Dragged[0].GeoId; + auto geo = getSketchObject()->getGeometry(GeoId); + auto gf = GeometryFacade::getFacade(geo); + + // BSpline weights have a radius corresponding to the weight value + // However, in order for them proportional to the B-Spline size, + // the scenograph has a size scalefactor times the weight + // This code normalizes the information sent to the solver. + if (gf->getInternalType() == InternalType::BSplineControlPoint) { + auto circle = static_cast(geo); + Base::Vector3d center = circle->getCenter(); + + Base::Vector3d dir = vec - center; + + double scalefactor = 1.0; + + if (circle->hasExtension( + SketcherGui::ViewProviderSketchGeometryExtension::getClassTypeId())) { + auto vpext = std::static_pointer_cast< + const SketcherGui::ViewProviderSketchGeometryExtension>( + circle + ->getExtension(SketcherGui::ViewProviderSketchGeometryExtension:: + getClassTypeId()) + .lock()); + + scalefactor = vpext->getRepresentationFactor(); + } + + vec = center + dir / scalefactor; + } + } + } + + if (getSketchObject()->moveGeometriesTemporary(drag.Dragged, vec, drag.relative) == 0) { + setPositionText(Base::Vector2d(x, y)); + draw(true, false); + } +} + +void ViewProviderSketch::commitDragMove(double x, double y) +{ + const char* cmdName = (drag.Dragged.size() == 1) ? + (drag.Dragged[0].Pos == Sketcher::PointPos::none ? + QT_TRANSLATE_NOOP("Command", "Drag Curve") : QT_TRANSLATE_NOOP("Command", "Drag Point")) + : QT_TRANSLATE_NOOP("Command", "Drag geometries"); + + getDocument()->openCommand(cmdName); + + Base::Vector3d vec(x - drag.xInit, y - drag.yInit, 0); + + if (drag.Dragged.size() == 1) { + // special single bspline point handling. + Sketcher::PointPos PosId = drag.Dragged[0].Pos; + + if (PosId == Sketcher::PointPos::none) { + int GeoId = drag.Dragged[0].GeoId; + auto geo = getSketchObject()->getGeometry(GeoId); + auto gf = GeometryFacade::getFacade(geo); + + // BSpline weights have a radius corresponding to the weight value + // However, in order for them proportional to the B-Spline size, + // the scenograph has a size scalefactor times the weight + // This code normalizes the information sent to the solver. + if (gf->getInternalType() == InternalType::BSplineControlPoint) { + auto circle = static_cast(geo); + Base::Vector3d center = circle->getCenter(); + + Base::Vector3d dir = vec - center; + + double scalefactor = 1.0; + + if (circle->hasExtension( + SketcherGui::ViewProviderSketchGeometryExtension:: + getClassTypeId())) { + auto vpext = std::static_pointer_cast< + const SketcherGui::ViewProviderSketchGeometryExtension>( + circle + ->getExtension( + SketcherGui::ViewProviderSketchGeometryExtension:: + getClassTypeId()) + .lock()); + + scalefactor = vpext->getRepresentationFactor(); + } + + vec = center + dir / scalefactor; + } + } + } + + std::stringstream cmd; + cmd << "moveGeometries("; + cmd << "["; + for (size_t i = 0; i < drag.Dragged.size(); ++i) { + if (i > 0) { + cmd << ", "; + } + cmd << "(" << drag.Dragged[i].GeoId << ", " << static_cast(drag.Dragged[i].Pos) << ")"; + } + cmd << "], App.Vector(" << vec.x << ", " << vec.y << ", 0)"; + + if (drag.relative) { + cmd << ", True"; + } + cmd << ")"; + + try { + Gui::cmdAppObjectArgs(getObject(), cmd.str().c_str()); + } + catch (const Base::Exception& e) { + getDocument()->abortCommand(); + Base::Console().DeveloperError("ViewProviderSketch", "Drag: %s\n", e.what()); + } + + getDocument()->commitCommand(); + + tryAutoRecomputeIfNotSolve(getSketchObject()); + drag.reset(); + resetPositionText(); +} + void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2d& toPos) { if (auto constr = getConstraint(constNum)) { diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index 0ceb339efd..9bd654f640 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -38,6 +38,7 @@ #include #include #include +#include #include "PropertyVisualLayerList.h" @@ -261,13 +262,12 @@ private: class Drag { public: - enum SpecialValues - { - InvalidPoint = -1, - InvalidCurve = -1 - }; - Drag() + { + reset(); + } + + void reset() { resetVector(); resetIds(); @@ -282,28 +282,15 @@ private: void resetIds() { - DragPoint = InvalidPoint; - DragCurve = InvalidCurve; + Dragged.clear(); DragConstraintSet.clear(); } - bool isDragPointValid() - { - return DragPoint > InvalidPoint; - } - bool isDragCurveValid() - { - return DragCurve > InvalidCurve; - } - double xInit, yInit; // starting point of the dragging operation bool relative; // whether the dragging move vector is relative or absolute - - int DragPoint; // dragged point id (only positive integers) - int DragCurve; // dragged curve id (only positive integers), negative external curves - // cannot be dragged. - std::set DragConstraintSet; // dragged constraints ids + std::vector Dragged; // dragged geometries + std::set DragConstraintSet; // dragged constraints ids }; // TODO: Selection and Preselection should use a same structure. Probably Drag should use the @@ -553,8 +540,7 @@ public: STATUS_SELECT_Constraint, /**< enum value a constraint was selected. */ STATUS_SELECT_Cross, /**< enum value the base coordinate system was selected. */ STATUS_SELECT_Wire, /**< enum value and edge was double clicked. */ - STATUS_SKETCH_DragPoint, /**< enum value while dragging a point. */ - STATUS_SKETCH_DragCurve, /**< enum value while dragging a curve. */ + STATUS_SKETCH_Drag, /**< enum value while dragging curves and or points. */ STATUS_SKETCH_DragConstraint, /**< enum value while dragging a compatible constraint. */ STATUS_SKETCH_UseHandler, /**< enum value a DrawSketchHandler is in control. */ STATUS_SKETCH_StartRubberBand, /**< enum value for initiating a rubber band selection */ @@ -615,7 +601,7 @@ public: * -> inline void setRecalculateInitialSolutionWhileMovingPoint(bool * recalculateInitialSolutionWhileMovingPoint) * -> inline int initTemporaryMove(int geoId, PointPos pos, bool fine=true) - * -> inline int moveTemporaryPoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool + * -> inline int moveGeometryTemporary(int geoId, PointPos pos, Base::Vector3d toPoint, bool * relative=false) * -> inline void updateSolverExtension(int geoId, std::unique_ptr && * ext) @@ -792,6 +778,15 @@ private: bool setPreselect(const std::string& subNameSuffix, float x = 0, float y = 0, float z = 0); //@} + /** @name dragging functions */ + //@{ + /// dragging helpers + void initDragging(int geoId, Sketcher::PointPos pos, Gui::View3DInventorViewer* viewer); + void doDragStep(double x, double y); + void commitDragMove(double x, double y); + + //@} + /** @name Selection functions */ //@{ /// box selection method diff --git a/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py b/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py index e9936cf61e..3e96bfd3e8 100644 --- a/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py +++ b/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py @@ -158,9 +158,9 @@ def CreateSlotPlateSet(SketchFeature): SketchFeature.setDatum(6, 0.872665) SketchFeature.addConstraint(Sketcher.Constraint("DistanceX", 0, 2, 0.0)) SketchFeature.setDatum(9, 0.000000) - SketchFeature.movePoint(0, 2, App.Vector(-0.007829, -33.376450, 0)) - SketchFeature.movePoint(0, 2, App.Vector(-0.738149, -10.493386, 0)) - SketchFeature.movePoint(0, 2, App.Vector(-0.007829, 2.165328, 0)) + SketchFeature.moveGeometry(0, 2, App.Vector(-0.007829, -33.376450, 0)) + SketchFeature.moveGeometry(0, 2, App.Vector(-0.738149, -10.493386, 0)) + SketchFeature.moveGeometry(0, 2, App.Vector(-0.007829, 2.165328, 0)) SketchFeature.addConstraint(Sketcher.Constraint("DistanceY", 0, 2, 2.165328)) SketchFeature.setDatum(10, 0.000000) @@ -229,7 +229,7 @@ class TestSketcherSolver(unittest.TestCase): CreateBoxSketchSet(self.Box) self.Doc.recompute() # moving a point of the sketch - self.Box.movePoint(0, 2, App.Vector(88.342697, 28.174158, 0)) + self.Box.moveGeometry(0, 2, App.Vector(88.342697, 28.174158, 0)) # fully constrain self.Box.addConstraint(Sketcher.Constraint("DistanceX", 1, 2, 90.0)) self.Box.addConstraint(Sketcher.Constraint("DistanceY", 1, 2, -50.0)) @@ -363,7 +363,7 @@ class TestSketcherSolver(unittest.TestCase): ActiveSketch.solve() ActiveSketch.exposeInternalGeometry(0) ActiveSketch.solve() - ActiveSketch.movePoint(0, 0, App.Vector(-26.266434, 14.345055, 0), 0) + ActiveSketch.moveGeometry(0, 0, App.Vector(-26.266434, 14.345055, 0), 0) ActiveSketch.solve() ActiveSketch.addConstraint(Sketcher.Constraint("Block", 0)) # Block the Ellipse in place ActiveSketch.addConstraint(