Merge pull request #25914 from AjinkyaDahale/sk-fix-25281

Sketcher: Handle angle constraint on sketchobject changes
This commit is contained in:
Chris Hennes
2025-12-15 10:15:13 -06:00
committed by GitHub
2 changed files with 92 additions and 13 deletions

View File

@@ -3417,7 +3417,7 @@ void createNewConstraintsForTrim(
}
// We have already transferred all constraints on endpoints to the new pieces.
// If there is still any left, this means one of the remaining pieces was degenerate.
if (!con->involvesGeoIdAndPosId(GeoId, PointPos::none)) {
if (!(con->Type == Angle || con->involvesGeoIdAndPosId(GeoId, PointPos::none))) {
continue;
}
// constraint has not yet been changed
@@ -3444,6 +3444,34 @@ void createNewConstraintsForTrim(
}
}
std::optional<size_t> findPieceContainingPoint(
const SketchObject* obj,
const Part::Geometry* geo,
const Base::Vector3d& point,
const std::vector<int>& newIds,
const std::vector<const Part::Geometry*>& newGeos
)
{
double conParam;
auto* geoAsCurve = static_cast<const Part::GeomCurve*>(geo);
geoAsCurve->closestParameter(point, conParam);
// Choose based on where the closest point lies
// If it's not there, just leave this constraint out
for (size_t i = 0; i < newIds.size(); ++i) {
double newGeoFirstParam = static_cast<const Part::GeomCurve*>(newGeos[i])->getFirstParameter();
double newGeoLastParam = static_cast<const Part::GeomCurve*>(newGeos[i])->getLastParameter();
// For periodic curves the point may need a full revolution
if ((newGeoFirstParam - conParam) > Precision::PApproximation() && obj->isClosedCurve(geo)) {
conParam += (geoAsCurve->getLastParameter() - geoAsCurve->getFirstParameter());
}
if ((newGeoFirstParam - conParam) <= Precision::PApproximation()
&& (conParam - newGeoLastParam) <= Precision::PApproximation()) {
return i;
}
}
return std::nullopt;
}
int SketchObject::trim(int GeoId, const Base::Vector3d& point)
{
if (!isGeoIdAllowedForTrim(this, GeoId)) {
@@ -3693,8 +3721,7 @@ bool SketchObject::deriveConstraintsForPieces(
case Vertical:
case Parallel: {
transferToAll = geo->is<Part::GeomLineSegment>();
break;
}
} break;
case Tangent:
case Perpendicular: {
if (geo->is<Part::GeomLineSegment>()) {
@@ -3728,9 +3755,63 @@ bool SketchObject::deriveConstraintsForPieces(
return true;
}
}
} break;
case Angle: {
const auto [thirdGeo, thirdPos] = con->getElement(2);
if (thirdGeo == oldId) {
// TODO: transfer to a coincident point,
// is it possible to do it somewhere else and avoid?
std::vector<int> GeoIdList;
std::vector<PointPos> PosIdList;
getDirectlyCoincidentPoints(thirdGeo, thirdPos, GeoIdList, PosIdList);
if (GeoIdList.size() <= 1) {
// TODO: Even in this case we can add a point
return false;
}
break;
}
// transfer only to the curve that actually intersects
Base::Vector3d point(getPoint(thirdGeo, thirdPos));
std::optional<size_t> idx = findPieceContainingPoint(this, geo, point, newIds, newGeos);
if (idx.has_value()) {
Constraint* trans = con->copy();
trans->substituteIndexAndPos(GeoIdList[0], PosIdList[0], GeoIdList[1], PosIdList[1]);
trans->substituteIndex(oldId, newIds[idx.value()]);
newConstraints.push_back(trans);
return true;
}
}
else if (thirdGeo != GeoEnum::GeoUndef) {
// Angle via point but the point won't change, can transfer to all or first
// transfer only to the curve that actually intersects
Base::Vector3d point(getPoint(thirdGeo, thirdPos));
std::optional<size_t> idx = findPieceContainingPoint(this, geo, point, newIds, newGeos);
if (idx.has_value()) {
Constraint* trans = con->copy();
trans->substituteIndex(oldId, newIds[idx.value()]);
newConstraints.push_back(trans);
return true;
}
break;
}
else if (std::ranges::any_of(newGeos, [](const Part::Geometry* geo) {
return !geo->is<Part::GeomLineSegment>();
})) {
// Angle without a specific point is only supported when _all_ geometries are lines.
// If the original was a line, we may reach this point, for example, when converting
// it to NURBS.
// NOTE: We may decide to change this logic in the future. Follows
// `Sketch::addConstraint`.
return false;
}
else {
// Straight up angle, can transfer to all or first
transferToAll = true;
break;
}
} break;
case Distance:
case DistanceX:
case DistanceY:
@@ -3778,9 +3859,7 @@ bool SketchObject::deriveConstraintsForPieces(
return true;
}
}
break;
}
} break;
case Radius:
case Diameter:
case Equal: {
@@ -3794,7 +3873,7 @@ bool SketchObject::deriveConstraintsForPieces(
newConstraints.push_back(trans);
break;
}
}
} break;
default:
// Release other constraints
break;
@@ -9493,7 +9572,7 @@ const std::map<int, Sketcher::PointPos> SketchObject::getAllCoincidentPoints(int
void SketchObject::getDirectlyCoincidentPoints(int GeoId, PointPos PosId,
std::vector<int>& GeoIdList,
std::vector<PointPos>& PosIdList)
std::vector<PointPos>& PosIdList) const
{
const std::vector<Constraint*>& constraints = this->Constraints.getValues();
@@ -9535,7 +9614,7 @@ void SketchObject::getDirectlyCoincidentPoints(int GeoId, PointPos PosId,
}
void SketchObject::getDirectlyCoincidentPoints(int VertexId, std::vector<int>& GeoIdList,
std::vector<PointPos>& PosIdList)
std::vector<PointPos>& PosIdList) const
{
int GeoId;
PointPos PosId;

View File

@@ -640,12 +640,12 @@ public:
PointPos PosId,
std::vector<int>& GeoIdList,
std::vector<PointPos>& PosIdList
);
) const;
void getDirectlyCoincidentPoints(
int VertexId,
std::vector<int>& GeoIdList,
std::vector<PointPos>& PosIdList
);
) const;
bool arePointsCoincident(int GeoId1, PointPos PosId1, int GeoId2, PointPos PosId2);
// Returns true if the sketch has 1 or more block constraint