Sketcher: Group dragging

This commit is contained in:
PaddleStroke
2024-12-03 18:06:41 +01:00
parent d2d8bb5f86
commit 70972b3926
8 changed files with 740 additions and 693 deletions

View File

@@ -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<GeoElementId> moved, 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 : moved) {
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<GCS::Point>::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 : moved) {
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 && moved.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<GeoElementId> moved = {GeoElementId(geoId, pos)};
return initMove(moved, fine);
}
void Sketch::resetInitMove()
{
isInitMove = false;
@@ -5140,17 +5093,15 @@ int Sketch::initBSplinePieceMove(int geoId,
return 0;
}
int Sketch::movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative)
int Sketch::movePoint(std::vector<GeoElementId> moved, 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(moved);
initToPoint = toPoint;
moveStep = 0;
}
@@ -5162,7 +5113,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(moved);
initToPoint = toPoint;
}
}
@@ -5170,92 +5121,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 : moved) {
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 +5204,12 @@ int Sketch::movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool rela
return solve();
}
int Sketch::movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative)
{
std::vector<GeoElementId> moved = {GeoElementId(geoId, pos)};
return movePoint(moved, toPoint, relative);
}
int Sketch::setDatum(int /*constrId*/, double /*value*/)
{
return -1;

View File

@@ -161,6 +161,7 @@ public:
/** initializes a point (or curve) drag by setting the current
* sketch status as a reference
*/
int initMove(std::vector<GeoElementId> moved, bool fine = true);
int initMove(int geoId, PointPos pos, bool fine = true);
/** Initializes a B-spline piece drag by setting the current
@@ -184,6 +185,7 @@ public:
* a condition for satisfying the new point location!
* The relative flag permits moving relatively to the current position
*/
int movePoint(std::vector<GeoElementId> moved, Base::Vector3d toPoint, bool relative = false);
int movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative = false);
/**

View File

@@ -1340,9 +1340,10 @@ int SketchObject::diagnoseAdditionalConstraints(
return lastDoF;
}
int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toPoint, bool relative,
int SketchObject::movePoint(std::vector<GeoElementId> moved, 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.movePoint(moved, 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<Part::Geometry*> geomlist = solvedSketch.extractGeometry();
Geometry.setValues(geomlist);
// Constraints.acceptGeometry(getCompleteGeometry());
for (std::vector<Part::Geometry*>::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::movePoint(int geoId, PointPos pos, const Base::Vector3d& toPoint, bool relative,
bool updateGeoBeforeMoving)
{
std::vector<GeoElementId> moved = { GeoElementId(geoId, pos) };
return movePoint(moved, toPoint, relative, updateGeoBeforeMoving);
}
template <>
Base::Vector3d SketchObject::getPointForGeometry<>(const Part::GeomPoint *geomPoint, PointPos PosId)
{

View File

@@ -352,6 +352,10 @@ public:
/// toggle the driving status of this constraint
int toggleVirtualSpace(int ConstrId);
/// move this point to a new location and solve
int movePoint(std::vector<GeoElementId> moved,
const Base::Vector3d& toPoint,
bool relative = false,
bool updateGeoBeforeMoving = false);
int movePoint(int GeoId,
PointPos PosId,
const Base::Vector3d& toPoint,
@@ -687,6 +691,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<GeoElementId> 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)
@@ -698,6 +704,9 @@ 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 moveTemporaryPoint(std::vector<GeoElementId> moved,
Base::Vector3d toPoint,
bool relative = false);
inline int
moveTemporaryPoint(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.
@@ -1061,16 +1070,19 @@ private:
mutable std::map<std::string, std::string> internalElementMap;
};
inline int SketchObject::initTemporaryMove(int geoId, PointPos pos, bool fine /*=true*/)
inline int SketchObject::initTemporaryMove(std::vector<GeoElementId> 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<GeoElementId> moved = {GeoElementId(geoId, pos)};
return initTemporaryMove(moved, fine);
}
inline int SketchObject::initTemporaryBSplinePieceMove(int geoId,
@@ -1088,12 +1100,19 @@ inline int SketchObject::initTemporaryBSplinePieceMove(int geoId,
return solvedSketch.initBSplinePieceMove(geoId, pos, firstPoint, fine);
}
inline int SketchObject::moveTemporaryPoint(std::vector<GeoElementId> moved,
Base::Vector3d toPoint,
bool relative /*=false*/)
{
return solvedSketch.movePoint(moved, toPoint, relative);
}
inline int SketchObject::moveTemporaryPoint(int geoId,
PointPos pos,
Base::Vector3d toPoint,
bool relative /*=false*/)
{
return solvedSketch.movePoint(geoId, pos, toPoint, relative);
std::vector<GeoElementId> moved = {GeoElementId(geoId, pos)};
return moveTemporaryPoint(moved, toPoint, relative);
}

View File

@@ -528,6 +528,22 @@ setLabelDistance(constraintIndex:int, value:float)
</UserDocu>
</Documentation>
</Methode>
<Methode Name="moveGeometries">
<Documentation>
<UserDocu>
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.
</UserDocu>
</Documentation>
</Methode>
<Methode Name="getPoint" Const="true">
<Documentation>
<UserDocu>

View File

@@ -1167,6 +1167,58 @@ PyObject* SketchObjectPy::setLabelDistance(PyObject* args)
Py_Return;
}
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<GeoElementId>
std::vector<GeoElementId> moved;
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;
}
moved.emplace_back(GeoElementId(geoId, static_cast<Sketcher::PointPos>(pointPos)));
}
// Convert Python vector to Base::Vector3d
Base::Vector3d v1 = static_cast<Base::VectorPy*>(pcObj)->value();
// Call the C++ method
if (this->getSketchObjectPtr()->movePoint(moved, v1, (relative > 0))) {
PyErr_SetString(PyExc_ValueError, "Failed to move geometries.");
return nullptr;
}
Py_RETURN_NONE;
}
PyObject* SketchObjectPy::movePoint(PyObject* args)
{
PyObject* pcObj;

View File

@@ -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<int>(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<Part::GeomLineSegment>()
|| geo->is<Part::GeomArcOfCircle>()
|| geo->is<Part::GeomCircle>()
|| geo->is<Part::GeomEllipse>()
|| geo->is<Part::GeomArcOfEllipse>()
|| geo->is<Part::GeomArcOfParabola>()
|| geo->is<Part::GeomArcOfHyperbola>()
|| geo->is<Part::GeomBSplineCurve>()) {
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<const Part::GeomCircle*>(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<int>(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<SoPickedPoint> 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<const Sketcher::SolverGeometryExtension>(
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<int> 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<int, Sketcher::PointPos> 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<Part::GeomLineSegment>()
|| geo->is<Part::GeomBSplineCurve>()) {
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<Part::GeomBSplineCurve>()) {
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<const Part::GeomCircle*>(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<const Sketcher::SolverGeometryExtension>(
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<int> 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<int, Sketcher::PointPos> 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<Part::GeomLineSegment>() || geo->is<Part::GeomBSplineCurve>()) {
setRelative();
}
if (geo->is<Part::GeomBSplineCurve>()) {
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<const Part::GeomCircle*>(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.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<const Part::GeomCircle*>(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<int>(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)) {

View File

@@ -38,6 +38,7 @@
#include <Mod/Part/Gui/ViewProviderAttachExtension.h>
#include <Mod/Part/Gui/ViewProviderGridExtension.h>
#include <Mod/Sketcher/App/GeoList.h>
#include <Mod/Sketcher/App/GeoEnum.h>
#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<int> DragConstraintSet; // dragged constraints ids
std::vector<Sketcher::GeoElementId> Dragged; // dragged geometries
std::set<int> 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 */
@@ -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