Sketcher: Add backwards-compat path for external geo

Before 0aed23c (PR #19582), external geometry projection used a different algorithm and produced slightly different geometry for some kinds of projections (B-splines in particular). This adds a backwards-compatibility path that allows old files to continue to use the old algorithm, while using the new and improved algorithm with new files.
This commit is contained in:
Chris Hennes
2026-03-17 15:22:11 +01:00
committed by Kacper Donat
parent 49d7d77274
commit 0cb8f7e240
3 changed files with 22 additions and 8 deletions
+6
View File
@@ -117,6 +117,11 @@ SketchObject::SketchObject() : geoLastId(0)
"Internal Geometry",
App::Prop_None,
"Enables selection of closed profiles within a sketch as input for operations");
ADD_PROPERTY_TYPE(_ExternalGeoVersion,
(0),
"Compatibility",
(App::PropertyType)(App::Prop_Hidden | App::Prop_ReadOnly),
"Version of external geometry projection algorithm");
Geometry.setOrderRelevant(true);
@@ -167,6 +172,7 @@ void SketchObject::setupObject()
"User parameter:BaseApp/Preferences/Mod/Sketcher");
ArcFitTolerance.setValue(hGrpp->GetFloat("ArcFitTolerance", Precision::Confusion()*10.0));
MakeInternals.setValue(hGrpp->GetBool("MakeInternals", false));
_ExternalGeoVersion.setValue(1);
inherited::setupObject();
}
+1
View File
@@ -109,6 +109,7 @@ public:
Part ::PropertyPartShape InternalShape;
App ::PropertyPrecision InternalTolerance;
App ::PropertyBool MakeInternals;
App ::PropertyInteger _ExternalGeoVersion;
/** @name methods override Feature */
//@{
short mustExecute() const override;
+15 -8
View File
@@ -1637,7 +1637,8 @@ void processEdge(const TopoDS_Edge& edge,
const gp_Pln& sketchPlane,
const Base::Rotation& invRot,
gp_Ax3& sketchAx3,
TopoDS_Shape& aProjFace)
TopoDS_Shape& aProjFace,
int externalGeoVersion = 1)
{
using std::numbers::pi;
@@ -1990,8 +1991,11 @@ void processEdge(const TopoDS_Edge& edge,
auto shape = Part::TopoShape(edge);
bool planar = shape.findPlane(plane);
// Check if the edge is planar and plane is perpendicular to the projection plane
if (planar && plane.Axis().IsNormal(sketchPlane.Axis(), Precision::Angular())) {
// Check if the edge is planar and plane is perpendicular to the projection plane.
// The getBoundBoxOptimal approach (version >= 1) produces better results for new
// sketches, but old files (version 0) must use NormalProjection to preserve element maps.
if (externalGeoVersion >= 1
&& planar && plane.Axis().IsNormal(sketchPlane.Axis(), Precision::Angular())) {
// Project an edge to a line. Only works if the edge is planar and its plane is
// perpendicular to the projection plane. OCC has trouble handling
// BSpline projection to a straight line. Although it does correctly projects
@@ -2194,7 +2198,8 @@ void processFace (const Rotation& invRot,
gp_Ax3& sketchAx3,
TopoDS_Shape& aProjFace,
std::vector<std::unique_ptr<Part::Geometry>>& geos,
TopoDS_Shape& refSubShape)
TopoDS_Shape& refSubShape,
int externalGeoVersion = 1)
{
const TopoDS_Face& face = TopoDS::Face(refSubShape);
BRepAdaptor_Surface surface(face);
@@ -2209,7 +2214,7 @@ void processFace (const Rotation& invRot,
for (edgeExp.Init(face, TopAbs_EDGE); edgeExp.More(); edgeExp.Next()) {
TopoDS_Edge edge = TopoDS::Edge(edgeExp.Current());
// Process each edge
processEdge(edge, geos, gPlane, invPlm, mov, sketchPlane, invRot, sketchAx3, aProjFace);
processEdge(edge, geos, gPlane, invPlm, mov, sketchPlane, invRot, sketchAx3, aProjFace, externalGeoVersion);
}
if (fabs(dnormal.Angle(snormal) - std::numbers::pi/2) < Precision::Confusion()) {
@@ -2295,6 +2300,8 @@ void SketchObject::rebuildExternalGeometry(std::optional<ExternalToAdd> extToAdd
{
Base::StateLocker lock(managedoperation, true); // no need to check input data validity as this is an sketchobject managed operation.
int extGeoVersion = _ExternalGeoVersion.getValue();
fixMissingAxisInExternalGeo();
// Analyze the state of existing external geometries to infer the desired state for new ones.
@@ -2528,11 +2535,11 @@ void SketchObject::rebuildExternalGeometry(std::optional<ExternalToAdd> extToAdd
if (projection && !refSubShape.IsNull()) {
switch (refSubShape.ShapeType()) {
case TopAbs_FACE: {
processFace(invRot, invPlm, mov, sketchPlane, gPlane, sketchAx3, aProjFace, geos, refSubShape);
processFace(invRot, invPlm, mov, sketchPlane, gPlane, sketchAx3, aProjFace, geos, refSubShape, extGeoVersion);
} break;
case TopAbs_EDGE: {
const TopoDS_Edge& edge = TopoDS::Edge(refSubShape);
processEdge(edge, geos, gPlane, invPlm, mov, sketchPlane, invRot, sketchAx3, aProjFace);
processEdge(edge, geos, gPlane, invPlm, mov, sketchPlane, invRot, sketchAx3, aProjFace, extGeoVersion);
} break;
case TopAbs_VERTEX: {
importVertex(refSubShape);
@@ -2560,7 +2567,7 @@ void SketchObject::rebuildExternalGeometry(std::optional<ExternalToAdd> extToAdd
auto edges = intersectionShape.getSubTopoShapes(TopAbs_EDGE);
for (const auto& s : edges) {
TopoDS_Edge edge = TopoDS::Edge(s.getShape());
processEdge(edge, geos, gPlane, invPlm, mov, sketchPlane, invRot, sketchAx3, aProjFace);
processEdge(edge, geos, gPlane, invPlm, mov, sketchPlane, invRot, sketchAx3, aProjFace, extGeoVersion);
}
// Section of some face (e.g. sphere) produce more than one arcs
// from the same circle. So we try to fit the arcs with a single