Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Problem] Regression on toNurbs() #9760

Open
2 tasks done
edwilliams16 opened this issue Jun 11, 2023 · 22 comments
Open
2 tasks done

[Problem] Regression on toNurbs() #9760

edwilliams16 opened this issue Jun 11, 2023 · 22 comments
Labels
3rd party: OCC Bug This issue or PR is related to a bug Regression Bugs describing a regression or PRs fixing one

Comments

@edwilliams16
Copy link
Contributor

edwilliams16 commented Jun 11, 2023

Is there an existing issue for this?

  • I have searched the existing issues

Version

0.21 (Development)

Full version info

[code]
OS: macOS 13.2.1
Word size of FreeCAD: 64-bit
Version: 0.21.0.33380 (Git)
Build type: Release
Branch: master
Hash: 16b06993e23eabd411586c7908be08ad8f609ce0
Python 3.11.3, Qt 5.15.8, Coin 4.0.0, Vtk 9.2.2, OCC 7.7.1
Locale: C/Default (C)
Installed mods: 
  * MeshRemodel 1.8919.0
  * DynamicData 2.46.0
  * lattice2.backup1682566094.626239 1.0.0 (Disabled)
  * fcgear 1.0.0
  * workfeature
  * Pyramids-and-Polyhedrons
  * QuickMeasure-main
  * GDML 1.8.0
  * offline-documentation
  * Manipulator 1.5.0
  * fasteners 0.4.56
  * lattice2 1.0.0
  * CurvedShapes 1.0.4
  * Alternate_OpenSCAD 1.0.0
  * toSketch 1.0.1
  * Help 1.0.3
  * Curves 0.6.10
[/code]

Subproject(s) affected?

None

Problem description

If you select an edge and send it to the Python console then

c =sub.toNurbs()
>>> c.Curve
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'Part.Shape' object has no attribute 'Curve'
>>> c
<Shape object at 0x60000257b180>
>>> c.Edges
[<Edge object at 0x6000025036c0>]
>>> 

the created edge has no underlying Curve. This breaks JoinCurves in the Curves WB and likely other things. It may be associated with OCC 7.7.x. See forum https://forum.freecad.org/viewtopic.php?p=687077#p687077

Anything else?

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct
@luzpaz luzpaz added 3rd party: OCC Regression Bugs describing a regression or PRs fixing one Bug This issue or PR is related to a bug labels Jun 11, 2023
@adrianinsaval
Copy link
Member

@bgbsww suspected occt 7.7 bug, would be nice to know if it works on 7.8

@bgbsww
Copy link
Contributor

bgbsww commented Jan 8, 2024

Unfortunately, I get the exact no attribute error above. @adrianinsaval
Oh, this bug doesn't quite match the forum, which notes:

c = sub.toNurbs().Edges[0]
>>> c.Curve
Traceback (most recent call last):
  File "<input>", line 1, in <module>
Base.FreeCADError: Unknown exception while reading attribute 'Curve' of object 'TopoShape'
>>>

But that also fails with the Unknown exception shown on the forum. So no 7.8 fix.

OS: Ubuntu 22.04.3 LTS (ubuntu:GNOME/ubuntu)
Word size of FreeCAD: 64-bit
Version: 0.22.0dev.35500 (Git)
Build type: Debug
Branch: bgbsww-occt7.8.0
Hash: 2a6fa0d9832920dd50d8f661e639d14c4eff9a04
Python 3.10.12, Qt 5.15.3, Coin 4.0.0, Vtk 7.1.1, OCC 7.8.0
Locale: English/United States (en_US)
Installed mods: 
  * Curves 0.6.21

@bgbsww
Copy link
Contributor

bgbsww commented Jan 8, 2024

This appears to be the result of code added in Open-Cascade-SAS/OCCT@2651bfd with the new method void BRepBuilderAPI_NurbsConvert::CorrectVertexTol()

Which I think means it is unlikely to go away in the future. The old version used to return legit edges; the new one seems to return empty ones, leading to the exception - there is no curve defined.

I do wonder if this can possibly be manipulated by specifying tolerances, but I can't tell if this represents new OCCT bugs, evolving misuse by FreeCAD due to relying on defaults, or something else.

Hmm. Stepping into CorrectVertexTol, it does nothing in a failing test case. More digging.

@edwilliams16
Copy link
Contributor Author

@bgbsww
Copy link
Contributor

bgbsww commented Jan 10, 2024

Lots of debugging history I wrote a test that triggers the failure in 7.7.x. Then I determined that the test only fails when the UI is up. Freecad -c -t runs just fine. That seems like a big clue.

Run without the UI, we try toNurbs on:

"className": "TopoDS_Shape""TShape": {"className": "BRep_TEdge", "className": "TopoDS_TShape", "this": "0xx555555a027f0", 
"ShapeType": 6, "NbChildren": 2, "Flags": 10, "Free": 0, "Free": 0, "Locked": 0, "Modified": 1, "Checked": 0, 
"Orientable": 1, "Closed": 0, "Infinite": 0, "Convex": 0, "Tolerance": 1e-07, "Flags": 3, "CurveRepresentation": 
{"className": "BRep_Curve3D", "className": "BRep_GCurve", "className": "BRep_CurveRepresentation", 
"Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], 
"shape": 0, "scale": 1}, "IsIdentity": 1}, "First": 0, "Last": 1, "Curve": {"className": "Geom_BSplineCurve", "className": 
"Geom_BoundedCurve", "className": "Geom_Curve", "className": "Geom_Geometry", "rational": 0, "periodic": 0, 
"knotSet": 3, "smooth": 6, "deg": 2, "poles->Size": 3, "flatknots->Size": 6, "knots->Size": 2, "mults->Size": 2, "maxderivinv": 0,
 "maxderivinvok": 0}}
 
 }"Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], 
"shape": 7, "scale": 1}, "IsIdentity": 0}"Orient": 0
0 0

and everything passes. With the UI up, the shape has more to it:

"className": "TopoDS_Shape""TShape": {"className": "BRep_TEdge", "className": "TopoDS_TShape", "this": "0xx5555586a4660", 
"ShapeType": 6, "NbChildren": 2, "Flags": 10, "Free": 0, "Free": 0, "Locked": 0, "Modified": 1, "Checked": 0, 
"Orientable": 1, "Closed": 0, "Infinite": 0, "Convex": 0, "Tolerance": 1e-07, "Flags": 3, "CurveRepresentation": 
{"className": "BRep_Curve3D", "className": "BRep_GCurve", "className": "BRep_CurveRepresentation", 
"Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], 
"shape": 0, "scale": 1}, "IsIdentity": 1}, "First": 0, "Last": 1, "Curve": {"className": "Geom_BSplineCurve", "className":
"Geom_BoundedCurve", "className": "Geom_Curve", "className": "Geom_Geometry", "rational": 0, "periodic": 0, 
"knotSet": 3, "smooth": 6, "deg": 2, "poles->Size": 3, "flatknots->Size": 6, "knots->Size": 2, "mults->Size": 2, "maxderivinv": 0,
 "maxderivinvok": 0}}, 
 
 "CurveRepresentation": {"className": "BRep_Polygon3D", "className": "BRep_CurveRepresentation", 
"Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], 
"shape": 0, "scale": 1}, "IsIdentity": 1}, "Polygon3D": {"className": "Poly_Polygon3D", "Deflection": 0.00985319, 
"Nodes.Size": 25, "Parameters->Size": 25}}
 
 }"Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 7, "scale": 1}, "IsIdentity": 0}"Orient": 0

So what's up with the Polygon3D with deflection, I wonder.

Good:
Thread 1 "FreeCAD" hit Breakpoint 1, BRepTools_NurbsConvertModification::NewPolygon (this=0x555555a066b0, theEdge=..., thePoly=...) at /home/brad/git/OCCT772/src/BRepTools/BRepTools_NurbsConvertModification.cxx:502
502 {
(gdb) n
503 if (!BRepTools_CopyModification::NewPolygon(theEdge, thePoly))
(gdb)
505 return Standard_False;
(gdb)

Bad:
503 if (!BRepTools_CopyModification::NewPolygon(theEdge, thePoly))
(gdb)
509 if (thePoly->HasParameters())
(gdb)

#0 BRepTools_NurbsConvertModification::NewPolygon(TopoDS_Edge const&, opencascade::handle<Poly_Polygon3D>&) (this=0x5555580ea8f0, theEdge=..., thePoly=...)
at /home/brad/git/OCCT772/src/BRepTools/BRepTools_NurbsConvertModification.cxx:502
#1 0x00007fff742c4407 in BRepTools_Modifier::Rebuild(TopoDS_Shape const&, opencascade::handle<BRepTools_Modification> const&, bool&, Message_ProgressRange const&)
(this=0x7fffffffad80, S=..., M=..., theNewGeom=@0x7fffffffaa06: false, theProgress=...) at /home/brad/git/OCCT772/src/BRepTools/BRepTools_Modifier.cxx:323
#2 0x00007fff742c3798 in BRepTools_Modifier::Perform(opencascade::handle<BRepTools_Modification> const&, Message_ProgressRange const&)
(this=0x7fffffffad80, M=..., theProgress=...)
at /home/brad/git/OCCT772/src/BRepTools/BRepTools_Modifier.cxx:142
#3 0x00007fff1b6dbb62 in BRepBuilderAPI_ModifyShape::DoModif()
(this=0x7fffffffad30)
at /home/brad/git/OCCT772/src/BRepBuilderAPI/BRepBuilderAPI_ModifyShape.cxx:76
#4 0x00007fff1b6dbd79 in BRepBuilderAPI_ModifyShape::DoModif(TopoDS_Shape const&, opencascade::handle<BRepTools_Modification> const&)
(this=0x7fffffffad30, S=..., M=...)
at /home/brad/git/OCCT772/src/BRepBuilderAPI/BRepBuilderAPI_ModifyShape.cxx:125
#5 0x00007fff1b6dc3c4 in BRepBuilderAPI_NurbsConvert::Perform(TopoDS_Shape cons

And the actual error is thrown in BRepAdaptor_Curve::Initialize after a failed call to BRep_Tool::CurveOnSurface

@bgbsww
Copy link
Contributor

bgbsww commented Jan 10, 2024

Lots of debugging history In TestPartApp.py: ``` def testIssue9760(self): doc = self.Doc doc.addObject('Sketcher::SketchObject', 'Sketch') doc.Sketch.Placement = App.Placement(App.Vector(0.000000, 0.000000, 0.000000), App.Rotation(0.000000, 0.000000, 0.000000, 1.000000)) doc.Sketch.MapMode = "Deactivated" ActiveSketch = doc.getObject('Sketch') p1 = App.Vector(0.367431,3.345679,0) p2 = App.Vector(5.658839,8.910781,0) p3 = App.Vector(11.223940,3.966051,0) z = App.Vector(0,0,1) ActiveSketch.addGeometry(Part.Circle(p1,z,10),True) ActiveSketch.addConstraint(Sketcher.Constraint('Weight',0,1.000000)) ActiveSketch.addGeometry(Part.Circle(p2,z,10),True) ActiveSketch.addConstraint(Sketcher.Constraint('Equal',0,1)) ActiveSketch.addGeometry(Part.Circle(p3,z,10),True) ActiveSketch.addConstraint(Sketcher.Constraint('Equal',0,2)) ActiveSketch.addGeometry(Part.BSplineCurve([p1,p2,p3],None,None,False,2,None,False),False) # App.Vector(0.367431,3.34568),App.Vector(5.65884,8.91078),App.Vector(11.2239,3.96605)],None,None,False,2,None,False),False) conList = [] conList.append(Sketcher.Constraint('InternalAlignment:Sketcher::BSplineControlPoint',0,3,3,0)) conList.append(Sketcher.Constraint('InternalAlignment:Sketcher::BSplineControlPoint',1,3,3,1)) conList.append(Sketcher.Constraint('InternalAlignment:Sketcher::BSplineControlPoint',2,3,3,2)) ActiveSketch.addConstraint(conList) del conList ActiveSketch.exposeInternalGeometry(3)
    doc.recompute()
    obj = doc.getObject("Sketch")
    shp = obj.Shape
    sub = obj.getSubObject("Edge1")
    curve = sub.toNurbs().Edges[0].Curve
    self.assertEqual(p1, curve.getPole(1))
    self.assertEqual(p2, curve.getPole(2))
    self.assertEqual(p3, curve.getPole(3))
</details>

@bgbsww
Copy link
Contributor

bgbsww commented Jan 10, 2024

Lots of debugging history Okay, the Polygon3d is normal, shows up in a 7.6.3 build and works fine.

The differences I can determine between the two shape objects are:

Bad:

 'TShape # 1 : EDGE      11010000 0x555557e3ba00\n'
 '    +3 -2 \n'
 '    Tolerance : 2.22045e-16\n'
 '     same parametrisation of curves\n'
 '     same range on curves\n'
 '    - Polygon 3D : 1\n'
 'TShape # 2 : VERTEX    01011010 0x5555588ce900\n'
 '    \n'
 '    Tolerance : 1e-07\n'
 '    - Point 3D : 12.0938, -1.17389, 0\n'
 '\n'
 'TShape # 3 : VERTEX    01011010 0x5555588ce870\n'
 '    \n'
 '    Tolerance : 1e-07\n'
 '    - Point 3D : 0.511955, -0.530112, 0\n'
 '\n'
 '\n'
 ' -------\n'
 'Dump of 0 Curve2ds \n'
 ' -------\n'

Good:

 'TShape # 1 : EDGE      01010000 0x55f191b3b2b0\n'
 '    +3 -2 \n'
 '    Tolerance : 1e-07\n'
 '     same parametrisation of curves\n'
 '     same range on curves\n'
 '    - Curve 3D : 1, range : 0 1\n'
 '    - Polygon 3D : 1\n'
 'TShape # 2 : VERTEX    01011010 0x55f191b3da00\n'
 '    \n'
 '    Tolerance : 1e-07\n'
 '    - Point 3D : 12.0938, -1.17389, 0\n'
 '\n'
 'TShape # 3 : VERTEX    01011010 0x55f191b3d970\n'
 '    \n'
 '    Tolerance : 1e-07\n'
 '    - Point 3D : 0.511955, -0.530112, 0\n'
 '\n'
 '\n'
 ' -------\n'
 'Dump of 0 Curve2ds \n'
 ' -------\n'
 '\n'
 '\n'
 ' -------\n'
 'Dump of 1 Curves \n'
 ' -------\n'
 '\n'
 '   1 : BSplineCurve\n'
 '  Degree 3, 5 Poles, 3  Knots\n'
 'Poles :\n'
 '\n'
 '   1 : 0.511955, -0.530112, 0 \n'
 '   2 : 2.34519, 2.82979, 0 \n'
 '   3 : 8.39056, 1.77522, 0 \n'
 '   4 : 14.0129, 2.8114, 0 \n'
 '   5 : 12.0938, -1.17389, 0 \n'
 'Knots :\n'
 '\n'
 '   1 :  0 4\n'
 '   2 :  0.5 1\n'
 '   3 :  1 4\n'
 '\n'
 ' -------\n'`

I wasn't planning on becoming the tolerance guy, but that's a pretty glaring value. Digging...

Using fixTolerance on the nurbs shape corrects the tolerance but doesn't create the missing curve.

@bgbsww
Copy link
Contributor

bgbsww commented Jan 11, 2024

Ok! The key difference is that in 7.7.0 the method BRepTools_NurbsConvertModification::NewPolygon was added to override

Standard_Boolean BRepTools_Modification::NewPolygon(const TopoDS_Edge&, Handle(Poly_Polygon3D)&)
{
  return Standard_False;
}

If that override is replaced by return Standard_False then everything works properly. Now to look for a workaround or a definite OCCT bug report.

@bgbsww
Copy link
Contributor

bgbsww commented Jan 11, 2024

What did that take 10 minutes? Here's the bug and OCCT needs to fix it:

//=======================================================================
//function : NewPolygon
//purpose  : 
//=======================================================================

Standard_Boolean BRepTools_NurbsConvertModification::NewPolygon(const TopoDS_Edge&      theEdge,
                                                                Handle(Poly_Polygon3D)& thePoly)
{
  if (!BRepTools_CopyModification::NewPolygon(theEdge, thePoly))
  {
    return Standard_False;
  }

  // update parameters of polygon
  if (thePoly->HasParameters())
  {
    Standard_Real aTol = BRep_Tool::Tolerance(theEdge);
    Standard_Real aFirst, aLast;
    Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theEdge, aFirst, aLast);
    Handle(Geom_Curve) aNewCurve = newCurve(myMap, theEdge, aFirst, aLast);
    if (!aCurve.IsNull() && !aNewCurve.IsNull()) // skip processing degenerated edges
    {
      TColStd_Array1OfReal& aParams = thePoly->ChangeParameters();
      for (Standard_Integer anInd = aParams.Lower(); anInd <= aParams.Upper(); ++anInd)
      {
        Standard_Real& aParam = aParams(anInd);
        gp_Pnt aPoint = aCurve->Value(aParam);
        newParameter(aPoint, aNewCurve, aFirst, aLast, aTol, aParam);
      }
    }
  }
  return Standard_True;
}

Should be ( note the else and return when a curve create fails ):

//=======================================================================
//function : NewPolygon
//purpose  : 
//=======================================================================

Standard_Boolean BRepTools_NurbsConvertModification::NewPolygon(const TopoDS_Edge&      theEdge,
                                                                Handle(Poly_Polygon3D)& thePoly)
{
  if (!BRepTools_CopyModification::NewPolygon(theEdge, thePoly))
  {
    return Standard_False;
  }

  // update parameters of polygon
  if (thePoly->HasParameters())
  {
    Standard_Real aTol = BRep_Tool::Tolerance(theEdge);
    Standard_Real aFirst, aLast;
    Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theEdge, aFirst, aLast);
    Handle(Geom_Curve) aNewCurve = newCurve(myMap, theEdge, aFirst, aLast);
    if (!aCurve.IsNull() && !aNewCurve.IsNull()) // skip processing degenerated edges
    {
      TColStd_Array1OfReal& aParams = thePoly->ChangeParameters();
      for (Standard_Integer anInd = aParams.Lower(); anInd <= aParams.Upper(); ++anInd)
      {
        Standard_Real& aParam = aParams(anInd);
        gp_Pnt aPoint = aCurve->Value(aParam);
        newParameter(aPoint, aNewCurve, aFirst, aLast, aTol, aParam);
      }
    } else return Standard_False;
  }
  return Standard_True;
}

@chennes did I read somewhere that you're set up as an OpenCascade contributor? Or is there someone else that can present this to them?

@chennes
Copy link
Member

chennes commented Jan 11, 2024

I have signed their CLA, but won't be able to submit this patch until next week - I am away from the computer that I use for OCCT work. Can anyone write a DRAW script demonstrating the error?

@bgbsww
Copy link
Contributor

bgbsww commented Jan 11, 2024

Lots of debugging history I think that ``` bsplinecurve bc 2 2 0 3 1 3 0 3 0 1 5 9 0 1 12 4 0 1 mkedge e1 bc nurbsconvert nb e1 dump nb lprops nb ``` is a start, but of course it doesn't fail :( More digging to figure out how to show the curve of the edge inside nb. Explode will only provide the vertexes.

@bgbsww
Copy link
Contributor

bgbsww commented Jan 12, 2024

Lots of debugging history Comparing what should be about the same OCCT shape between FreeCAD and DRAW, I think I see why this differs when you run FreeCAD headless that causes it to work. Using the C++ DumpJson calls:

Nurbs fail in FreeCAD with display:

Perform
"className": "TopoDS_Shape""TShape": {"className": "BRep_TEdge", "className": "TopoDS_TShape", "this": "0xx5555588a9110", "ShapeType": 6, "NbChildren": 2, "Flags": 11, "Free": 1, "Free": 1, "Locked": 0, "Modified": 1, "Checked": 0, "Orientable": 1, "Closed": 0, "Infinite": 0, "Convex": 0, "Tolerance": 1e-07, "Flags": 3, "CurveRepresentation": {"className": "BRep_Curve3D", "className": "BRep_GCurve", "className": "BRep_CurveRepresentation", "Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 0, "scale": 1}, "IsIdentity": 1}, "First": 0, "Last": 1, "Curve": {"className": "Geom_BSplineCurve", "className": "Geom_BoundedCurve", "className": "Geom_Curve", "className": "Geom_Geometry", "rational": 0, "periodic": 0, "knotSet": 3, "smooth": 6, "deg": 2, "poles->Size": 3, "flatknots->Size": 6, "knots->Size": 2, "mults->Size": 2, "maxderivinv": 0, "maxderivinvok": 0}}, "CurveRepresentation": {"className": "BRep_Polygon3D", "className": "BRep_CurveRepresentation", "Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 0, "scale": 1}, "IsIdentity": 1}, "Polygon3D": {"className": "Poly_Polygon3D", "Deflection": 0.0108654, "Nodes.Size": 24, "Parameters->Size": 24}}}"Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 7, "scale": 1}, "IsIdentity": 0}"Orient": 0
PostMod
"className": "TopoDS_Shape""TShape": {"className": "BRep_TEdge", "className": "TopoDS_TShape", "this": "0xx5555588a9110", "ShapeType": 6, "NbChildren": 2, "Flags": 11, "Free": 1, "Free": 1, "Locked": 0, "Modified": 1, "Checked": 0, "Orientable": 1, "Closed": 0, "Infinite": 0, "Convex": 0, "Tolerance": 1e-07, "Flags": 3, "CurveRepresentation": {"className": "BRep_Curve3D", "className": "BRep_GCurve", "className": "BRep_CurveRepresentation", "Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 0, "scale": 1}, "IsIdentity": 1}, "First": 0, "Last": 1, "Curve": {"className": "Geom_BSplineCurve", "className": "Geom_BoundedCurve", "className": "Geom_Curve", "className": "Geom_Geometry", "rational": 0, "periodic": 0, "knotSet": 3, "smooth": 6, "deg": 2, "poles->Size": 3, "flatknots->Size": 6, "knots->Size": 2, "mults->Size": 2, "maxderivinv": 0, "maxderivinvok": 0}}, "CurveRepresentation": {"className": "BRep_Polygon3D", "className": "BRep_CurveRepresentation", "Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 0, "scale": 1}, "IsIdentity": 1}, "Polygon3D": {"className": "Poly_Polygon3D", "Deflection": 0.0108654, "Nodes.Size": 24, "Parameters->Size": 24}}}"Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 7, "scale": 1}, "IsIdentity": 0}"Orient": 0
PostCorrect
"className": "TopoDS_Shape""TShape": {"className": "BRep_TEdge", "className": "TopoDS_TShape", "this": "0xx5555588a9110", "ShapeType": 6, "NbChildren": 2, "Flags": 11, "Free": 1, "Free": 1, "Locked": 0, "Modified": 1, "Checked": 0, "Orientable": 1, "Closed": 0, "Infinite": 0, "Convex": 0, "Tolerance": 1e-07, "Flags": 3, "CurveRepresentation": {"className": "BRep_Curve3D", "className": "BRep_GCurve", "className": "BRep_CurveRepresentation", "Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 0, "scale": 1}, "IsIdentity": 1}, "First": 0, "Last": 1, "Curve": {"className": "Geom_BSplineCurve", "className": "Geom_BoundedCurve", "className": "Geom_Curve", "className": "Geom_Geometry", "rational": 0, "periodic": 0, "knotSet": 3, "smooth": 6, "deg": 2, "poles->Size": 3, "flatknots->Size": 6, "knots->Size": 2, "mults->Size": 2, "maxderivinv": 0, "maxderivinvok": 0}}, "CurveRepresentation": {"className": "BRep_Polygon3D", "className": "BRep_CurveRepresentation", "Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 0, "scale": 1}, "IsIdentity": 1}, "Polygon3D": {"className": "Poly_Polygon3D", "Deflection": 0.0108654, "Nodes.Size": 24, "Parameters->Size": 24}}}"Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 7, "scale": 1}, "IsIdentity": 0}"Orient": 0

toNurbs succeed in Draw:

Perform
"className": "TopoDS_Shape""TShape": {"className": "BRep_TEdge", "className": "TopoDS_TShape", "this": "0xx555555989920", "ShapeType": 6, "NbChildren": 2, "Flags": 11, "Free": 1, "Free": 1, "Locked": 0, "Modified": 1, "Checked": 0, "Orientable": 1, "Closed": 0, "Infinite": 0, "Convex": 0, "Tolerance": 1e-07, "Flags": 3, "CurveRepresentation": {"className": "BRep_Curve3D", "className": "BRep_GCurve", "className": "BRep_CurveRepresentation", "Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 0, "scale": 1}, "IsIdentity": 1}, "First": 0, "Last": 1, "Curve": {"className": "Geom_BSplineCurve", "className": "Geom_BoundedCurve", "className": "Geom_Curve", "className": "Geom_Geometry", "rational": 0, "periodic": 0, "knotSet": 3, "smooth": 6, "deg": 2, "poles->Size": 3, "flatknots->Size": 6, "knots->Size": 2, "mults->Size": 2, "maxderivinv": 0, "maxderivinvok": 0}}}"Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 0, "scale": 1}, "IsIdentity": 1}"Orient": 0
PostMod
"className": "TopoDS_Shape""TShape": {"className": "BRep_TEdge", "className": "TopoDS_TShape", "this": "0xx555555989920", "ShapeType": 6, "NbChildren": 2, "Flags": 11, "Free": 1, "Free": 1, "Locked": 0, "Modified": 1, "Checked": 0, "Orientable": 1, "Closed": 0, "Infinite": 0, "Convex": 0, "Tolerance": 1e-07, "Flags": 3, "CurveRepresentation": {"className": "BRep_Curve3D", "className": "BRep_GCurve", "className": "BRep_CurveRepresentation", "Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 0, "scale": 1}, "IsIdentity": 1}, "First": 0, "Last": 1, "Curve": {"className": "Geom_BSplineCurve", "className": "Geom_BoundedCurve", "className": "Geom_Curve", "className": "Geom_Geometry", "rational": 0, "periodic": 0, "knotSet": 3, "smooth": 6, "deg": 2, "poles->Size": 3, "flatknots->Size": 6, "knots->Size": 2, "mults->Size": 2, "maxderivinv": 0, "maxderivinvok": 0}}}"Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 0, "scale": 1}, "IsIdentity": 1}"Orient": 0
PostCorrect
"className": "TopoDS_Shape""TShape": {"className": "BRep_TEdge", "className": "TopoDS_TShape", "this": "0xx555555989920", "ShapeType": 6, "NbChildren": 2, "Flags": 11, "Free": 1, "Free": 1, "Locked": 0, "Modified": 1, "Checked": 0, "Orientable": 1, "Closed": 0, "Infinite": 0, "Convex": 0, "Tolerance": 1e-07, "Flags": 3, "CurveRepresentation": {"className": "BRep_Curve3D", "className": "BRep_GCurve", "className": "BRep_CurveRepresentation", "Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 0, "scale": 1}, "IsIdentity": 1}, "First": 0, "Last": 1, "Curve": {"className": "Geom_BSplineCurve", "className": "Geom_BoundedCurve", "className": "Geom_Curve", "className": "Geom_Geometry", "rational": 0, "periodic": 0, "knotSet": 3, "smooth": 6, "deg": 2, "poles->Size": 3, "flatknots->Size": 6, "knots->Size": 2, "mults->Size": 2, "maxderivinv": 0, "maxderivinvok": 0}}}"Location": {"className": "TopLoc_Location", "Transformation": {"Location": [0, 0, 0], "Matrix": [1, 0, 0, 0, 1, 0, 0, 0, 1], "shape": 0, "scale": 1}, "IsIdentity": 1}"Orient": 0

The second "CurveRepresentation" of {"className": "BRep_Polygon3D" is what triggers the problem, and I don't think this can be replicated in Draw :(

I don't know where it comes from and if it can be avoided in FreeCAD

@bgbsww
Copy link
Contributor

bgbsww commented Jan 12, 2024

Lots of debugging history ``` >>> p1 = App.Vector(0, 3, 0) >>> p2 = App.Vector(5, 9, 0) >>> p3 = App.Vector(12, 4, 0) >>> bs = Part.BSplineCurve([p1,p2,p3],None,None,False,2,None,False) >>> e1 = Part.Edge(bs) >>> n2 = e1.toNurbs() >>> n2.Edges[0].Curve >>> s1 = Part.Shape(e1) >>> o1 = Part.show(s1,"testSpline") >>> n3 = o1.Shape.toNurbs() >>> n3.Edges[0].Curve Traceback (most recent call last): File "", line 1, in Base.FreeCADError: Unknown exception while reading attribute 'Curve' of object 'TopoShape' >>> e1.toNurbs().Edges[0].Curve Traceback (most recent call last): File "", line 1, in Base.FreeCADError: Unknown exception while reading attribute 'Curve' of object 'TopoShape' ``` The modifications to the edge object happen when we build a mesh to be able to display it here: https://github.com/FreeCAD/FreeCAD/blob/3ba0c3d7958dad891e125e065a41d95faac47c6e/src/Mod/Part/Gui/ViewProviderExt.cpp#L958C1-L958C1
gdb) bt
#0  BRep_CurveRepresentation::BRep_CurveRepresentation(TopLoc_Location const&)
    (this=0x7ffeee12c360 <Standard::Allocate(unsigned long)+36>, L=...)
    at /home/brad/git/OCCT780/src/BRep/BRep_CurveRepresentation.cxx:35
#1  0x00007fff05126e06 in BRep_Polygon3D::BRep_Polygon3D(opencascade::handle<Poly_Polygon3D> const&, TopLoc_Location const&)
    (this=0x5555588d4040, P=..., L=...)
    at /home/brad/git/OCCT780/src/BRep/BRep_Polygon3D.cxx:34
#2  0x00007fff0511ad52 in BRep_Builder::UpdateEdge(TopoDS_Edge const&, opencascade::handle<Poly_Polygon3D> const&, TopLoc_Location const&) const
    (this=0x7fffffff9877, E=..., P=..., L=...)
    at /home/brad/git/OCCT780/src/BRep/BRep_Builder.cxx:773
#3  0x00007fff049aba62 in BRep_Builder::UpdateEdge(TopoDS_Edge const&, opencascade::handle<Poly_Polygon3D> const&) const (this=0x7fffffff9877, E=..., P=...)
    at /home/brad/git/OCCT780/src/BRep/BRep_Builder.lxx:158
#4  0x00007fff049ab3c0 in BRepMesh_ShapeTool::UpdateEdge(TopoDS_Edge const&, opencascade::handle<Poly_Polygon3D> const&) (theEdge=..., thePolygon=...)
    at /home/brad/git/OCCT780/src/BRepMesh/BRepMesh_ShapeTool.cxx:297
#5  0x00007fff0499cfd7 in (anonymous namespace)::PolygonCommitter::commitPolygon3D(IMeshData::IEdgeHandle const&) const (this=0x7fffffff9b40, theDEdge=...)
    at /home/brad/git/OCCT780/src/BRepMesh/BRepMesh_ModelPostProcessor.cxx:79
#6  0x00007fff0499cdae in (anonymous namespace)::PolygonCommitter::operator()(Standard_Integer) const (this=0x7fffffff9b40, theEdgeIndex=0)
    at /home/brad/git/OCCT780/src/BRepMesh/BRepMesh_ModelPostProcessor.cxx:52
#7  0x00007fff0499dd87 in OSD_Parallel::For<(anonymous namespace)::PolygonCommitter>(Standard_Integer, Standard_Integer, (anonymous namespace)::PolygonCommitter const&, Standard_Boolean)
    (theBegin=0, theEnd=1, theFunctor=..., isForceSingleThreadExecution=true)
    at /home/brad/git/OCCT780/src/OSD/OSD_Parallel.hxx:361
#8  0x00007fff0499db88 in BRepMesh_ModelPostProcessor::performInternal(opencascade::handle<IMeshData_Model> const&, IMeshTools_Parameters const&, Message_ProgressRange const&)
     (this=0x555557fcd790, theModel=..., theParameters=..., theRange=...)
    at /home/brad/git/OCCT780/src/BRepMesh/BRepMesh_ModelPostProcessor.cxx:239
#9  0x00007fff04919c1a in IMeshTools_ModelAlgo::Perform(opencascade::handle<IMeshData_Model> const&, IMeshTools_Parameters const&, Message_ProgressRange const&) (this=0x555557fcd790, theModel=..., theParameters=..., theRange=...)
    at /home/brad/git/OCCT780/src/IMeshTools/IMeshTools_ModelAlgo.hxx:45
--Type <RET> for more, q to quit, c to continue without paging--
#10 0x00007fff0491a25c in IMeshTools_Context::PostProcessModel()
     (this=0x55555842cc40)
    at /home/brad/git/OCCT780/src/IMeshTools/IMeshTools_Context.hxx:124
#11 0x00007fff0491b064 in IMeshTools_MeshBuilder::Perform(Message_ProgressRange const&) (this=0x7fffffff9e80, theRange=...)
    at /home/brad/git/OCCT780/src/IMeshTools/IMeshTools_MeshBuilder.cxx:75
#12 0x00007fff04973093 in BRepMesh_IncrementalMesh::Perform(opencascade::handle<IMeshTools_Context> const&, Message_ProgressRange const&)
     (this=0x7fffffffa460, theContext=..., theRange=...)
    at /home/brad/git/OCCT780/src/BRepMesh/BRepMesh_IncrementalMesh.cxx:110
#13 0x00007fff04972ecb in BRepMesh_IncrementalMesh::Perform(Message_ProgressRange const&) (this=0x7fffffffa460, theRange=...)
    at /home/brad/git/OCCT780/src/BRepMesh/BRepMesh_IncrementalMesh.cxx:93
#14 0x00007fff04972dd4 in BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh(TopoDS_Shape const&, IMeshTools_Parameters const&, Message_ProgressRange const&)
    (this=0x7fffffffa460, theShape=..., theParameters=..., theRange=...)
    at /home/brad/git/OCCT780/src/BRepMesh/BRepMesh_IncrementalMesh.cxx:75
#15 0x00007ffeed180e9a in PartGui::ViewProviderPartExt::updateVisual()
     (this=0x555555e55600)
    at /home/brad/git/FreeCAD/src/Mod/Part/Gui/ViewProviderExt.cpp:958
#16 0x00007ffeed1805c6 in PartGui::ViewProviderPartExt::updateData(App::Property const*) (this=0x555555e55600, prop=0x555555cc6b70)

We should be able to simulate that in Draw...

bsplinecurve bc 2 2 0 3 1 3 0 3 0 1 5 9 0 1 12 4 0 1 
mkedge e1 bc
incmesh e1 0.0101817073481469 -angular 0.5000368240384726 -parallel 1 -decrease 1
nurbsconvert nb e1
lprops nb
dump nb

Which does result in the second curve representation with Polygon3D, but still no crash. On to the subtleties.

@bgbsww
Copy link
Contributor

bgbsww commented Jan 13, 2024

Invalid shapes created by NURBS conversion in 7.7.0 and after.

The added implementation of BRepTools_NurbsConvertModification::NewPolygon appears to miss the case where degenerated edges exist and returns the wrong flag value.

DRAWEXE test script:

pload ALL
bsplinecurve bc 2 2 0 3 1 3 0 3 0 1 5 9 0 1 12 4 0 1 
mkedge e1 bc
incmesh e1 0.03
nurbsconvert nb e1
checkshape nb

DRAWEXE test runs:

/home/brad/git/OCCT763/install/bin/DRAWEXE
This shape seems to be valid

/home/brad/git/OCCT772/install/bin/DRAWEXE
On Shape faulty_1 :
BRepCheck_No3DCurve
BRepCheck_CheckFail

Faulty shapes in variables faulty_1 to faulty_1 


/home/brad/git/OCCT780/install/bin/DRAWEXE
On Shape faulty_1 :
BRepCheck_No3DCurve
BRepCheck_CheckFail

Faulty shapes in variables faulty_1 to faulty_1 


/home/brad/git/OCCT780patched/install/bin/DRAWEXE
This shape seems to be valid

Patch:

diff --git a/src/BRepTools/BRepTools_NurbsConvertModification.cxx b/src/BRepTools/BRepTools_NurbsConvertModification.cxx
index 85a30c63c6..fe4166ded8 100644
--- a/src/BRepTools/BRepTools_NurbsConvertModification.cxx
+++ b/src/BRepTools/BRepTools_NurbsConvertModification.cxx
@@ -521,7 +521,7 @@ Standard_Boolean BRepTools_NurbsConvertModification::NewPolygon(const TopoDS_Edg
         gp_Pnt aPoint = aCurve->Value(aParam);
         newParameter(aPoint, aNewCurve, aFirst, aLast, aTol, aParam);
       }
-    }
+    } else return Standard_False;
   }
   return Standard_True;
 }

@chennes When you get to it, here's the complete package for OCCT. Please let me know if you need anything else.

For the peanut gallery, yes, this bug is fixed with that patch in place.

@chennes
Copy link
Member

chennes commented Jan 18, 2024

I hate Mantis 😁 -- https://tracker.dev.opencascade.org/view.php?id=33576

@adrianinsaval
Copy link
Member

Is the patch submitted somewhere else?

@chennes
Copy link
Member

chennes commented Jan 19, 2024

I have not yet submitted the patch as a PR, I have switched computers since the last time I did that, I have to get my keys set up. I was hoping the OCCT folks would render an opinion first, since it really looks like they made that change on purpose.

@bgbsww
Copy link
Contributor

bgbsww commented Jan 19, 2024

I agree the method was added on purpose, and it solves a problem. I think it's an implementation oversight that they missed this one case. It doesn't make sense to avoid doing the processing because you couldn't make the curve, and then claim you did something. That path wouldn't show up in the problem they were fixing. Method needs to stay, results need to be correct. We'll see what they say.

@chennes
Copy link
Member

chennes commented Jan 20, 2024

It was really the comment "// skip processing degenerated edges" that gave me pause. To me that sounds like they know they are just deciding not to do anything with them, for whatever reason. When I am back home I'll submit the PR anyway, in part just to see what their CI does with it.

@edwilliams16
Copy link
Contributor Author

@chennes
Still broken in
OS: macOS 14.4.1
Word size of FreeCAD: 64-bit
Version: 0.22.0dev.36904 (Git)
Build type: Release
Branch: main
Hash: 0622cb7
Python 3.11.8, Qt 5.15.13, Coin 4.0.2, Vtk 9.2.6, OCC 7.7.2
Locale: C/Default (C)
Installed mods:

  • MeshRemodel 1.9.23
  • Alternate_OpenSCAD.backup1715191085.460052 1.0.0 (Disabled)
  • DynamicData 2.62.0
  • fcgear 1.0.0
  • workfeature
  • QuickMeasure.backup1715191122.944101 2022.10.28 (Disabled)
  • Curves.backup1710533229.314989 0.6.24 (Disabled)
  • Pyramids-and-Polyhedrons
  • QuickMeasure 2022.10.28
  • GDML 2.0.0
  • offline-documentation
  • Manipulator 1.5.7
  • fasteners 0.5.20
  • MeshRemodel.backup1715191099.457215 1.9.22 (Disabled)
  • lattice2 1.0.0
  • CurvedShapes 1.0.9
  • Alternate_OpenSCAD 1.0.0
  • sheetmetal 0.4.13
  • toSketch 1.0.1
  • Help 1.0.3
  • Curves 0.6.36

Did you get a response from OCCT?

@chennes
Copy link
Member

chennes commented May 9, 2024

@adrianinsaval
Copy link
Member

I added the patch provided to the 7.8.1 package in conda-forge. I'll will start working on moving the weekly builds to that in a week or so

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3rd party: OCC Bug This issue or PR is related to a bug Regression Bugs describing a regression or PRs fixing one
Projects
None yet
Development

No branches or pull requests

5 participants