Rangebox error in sheet metal part with spline

Rangebox error in sheet metal part with spline

nmunro
Collaborator Collaborator
845 Views
8 Replies
Message 1 of 9

Rangebox error in sheet metal part with spline

nmunro
Collaborator
Collaborator

The attached part displays some odd behavior (see the embedded VBA macro T2). The size of the part and the flat pattern extents (40mm x 558.8mm) are reported correctly in Inventor's internal flat pattern properties, but the rangebox information for both the folded and flat model is wildly innacurate for the X value. This seems directly related to the spline based edge on the part.

 

What spline data is causing the disparity? I know that the rangebox object is only guaranteed to contain the body, but with such a large error it makes the use of the rangebox for any body based on spline geometry pretty much useless.

 

How is Inventor calculating extents internally? Is it a ray based approach, or a study of edge data? From a programming perspective, how can we get a result that will always return a reasonably accurate description of the size of the part?

 

Neil

 

 

        


https://c3mcad.com

0 Likes
Accepted solutions (1)
846 Views
8 Replies
Replies (8)
Message 2 of 9

xiaodong_liang
Autodesk Support
Autodesk Support
Hi Neil,

RangBox is an ortho box that can exactly cover a shape in WCS coordination. While it is true it looks the X value of a box is not same to what is measured manually when a spline is applied in the sketch. While Y or Z direction works well.

I will need to discuss with our engineer team about this.
0 Likes
Message 3 of 9

ekinsb
Alumni
Alumni
Accepted solution

The RangeBox call is intended to be as fast as possible to be used as a quick way to eliminate or add an object to set of objects for further, more expensive processing.  I'm fairly certain that the range box for any spline based geometry is based on the control polygon of the spline so in most cases it will be larger than the actual curve or surface.  It would take me a while to dig into how Inventor is getting the size of the sheet metal part, but obviously it's doing a more expensive calculation to get a tight range box.

 

A way to get an accurate bounding box is to calculate your own based on a mesh representation of the body.  This may seem complicated but it's really not.  Below is a VBA implementation I just put together quickly to illustrate.

 

Public Sub t2()
    Dim doc As PartDocument
    Set doc = ThisDocument
    
    Dim xWidth As Double
    Dim yLength As Double
    
    doc.ObjectVisibility.AllWorkFeatures = False
    doc.ObjectVisibility.ConstructionSurfaces = False
    doc.ObjectVisibility.SketchDimensions = False
    doc.ObjectVisibility.Sketches = False
    doc.ObjectVisibility.Sketches3D = False
    
    Dim boundingBox As Box
    Set boundingBox = doc.ComponentDefinition.SurfaceBodies.Item(1).RangeBox
    
    xWidth = Round(Abs(boundingBox.MaxPoint.X - boundingBox.MinPoint.X), 3)
    yLength = Round(Abs(boundingBox.MaxPoint.Y - boundingBox.MinPoint.Y), 3)
   
    Debug.Print "X = " & xWidth
    Debug.Print "Y = " & yLength
    
    Set boundingBox = TightRangeBox(doc.ComponentDefinition.SurfaceBodies.Item(1))

    xWidth = Round(Abs(boundingBox.MaxPoint.X - boundingBox.MinPoint.X), 3)
    yLength = Round(Abs(boundingBox.MaxPoint.Y - boundingBox.MinPoint.Y), 3)
   
    Debug.Print "Tight"
    Debug.Print "X = " & xWidth
    Debug.Print "Y = " & yLength
End Sub

Public Function TightRangeBox(Body As Inventor.SurfaceBody) As Inventor.Box
    ' Get the existing mesh of the highest resolution.
    Dim tolCount As Long
    Dim tols() As Double
    Call Body.GetExistingFacetTolerances(tolCount, tols)
    Dim i As Integer
    Dim bestTol As Double
    bestTol = tols(0)
    For i = 1 To tolCount - 1
        If tols(i) < bestTol Then
            bestTol = tols(i)
        End If
    Next
    
    Dim vertexCount As Long
    Dim facetCount As Long
    Dim vertexCoords() As Double
    Dim normalVectors() As Double
    Dim vertexIndices() As Long
    Call Body.GetExistingFacets(bestTol, vertexCount, facetCount, vertexCoords, normalVectors, vertexIndices)
    
    ' Loop through the vertices and build up the range box.
    Dim minX As Double
    Dim maxX As Double
    Dim minY As Double
    Dim maxY As Double
    Dim minZ As Double
    Dim maxZ As Double
    minX = vertexCoords(0)
    maxX = vertexCoords(0)
    minY = vertexCoords(1)
    maxY = vertexCoords(1)
    minZ = vertexCoords(2)
    maxZ = vertexCoords(2)
    For i = 1 To vertexCount - 1
        If vertexCoords(i * 3) < minX Then
            minX = vertexCoords(i * 3)
        End If
        
        If vertexCoords(i * 3) > maxX Then
            maxX = vertexCoords(i * 3)
        End If
    
        If vertexCoords(i * 3 + 1) < minY Then
            minY = vertexCoords(i * 3 + 1)
        End If
        
        If vertexCoords(i * 3 + 1) > maxY Then
            maxY = vertexCoords(i * 3 + 1)
        End If
    
        If vertexCoords(i * 3 + 2) < minZ Then
            minZ = vertexCoords(i * 3 + 2)
        End If
        
        If vertexCoords(i * 3 + 2) > maxZ Then
            maxZ = vertexCoords(i * 3 + 2)
        End If
    Next
    
    Dim newBox As Box
    Set newBox = ThisApplication.TransientGeometry.CreateBox()
    newBox.MinPoint = ThisApplication.TransientGeometry.CreatePoint(minX, minY, minZ)
    newBox.MaxPoint = ThisApplication.TransientGeometry.CreatePoint(maxX, maxY, maxZ)
    
    Set TightRangeBox = newBox
End Function

Brian Ekins
Inventor and Fusion 360 API Expert
Mod the Machine blog
Message 4 of 9

nmunro
Collaborator
Collaborator

Brian,

 

Thanks, I'll put that to use.

 

Neil

 

        


https://c3mcad.com

0 Likes
Message 5 of 9

nmunro
Collaborator
Collaborator

Brian,

 

Although I can easily work around this, using this method on a surfacebody obtained from the flat pattern fails (Doc.ComponentDefinition.FlatPattern.SurfacBodies[1]). The flat pattern surfacebody appears to be a valid surfacebody object, but the GetExistingFacets() method returns no information. The vertexCount and facetCount both = 0, and the returned arrays have no elements other than what was required to initialize the array.

 

The method works great for a surfacebody object obtained from the ComponentDefintion object.

 

Neil

 

        


https://c3mcad.com

0 Likes
Message 6 of 9

nmunro
Collaborator
Collaborator
Cancel that last comment, I seem to have it working with all surface bodies now. Thanks again.

        


https://c3mcad.com

0 Likes
Message 7 of 9

nmunro
Collaborator
Collaborator

I spoke a bit too soon. It does fail when using it with a transient surface body. If I can get a case number I can share some code that demonstrates the issue.

 

Neil

 

        


https://c3mcad.com

0 Likes
Message 8 of 9

ekinsb
Alumni
Alumni

That's actually expected because the code is getting the mesh being used for the display of the body.  For a transient body, there isn't a display mesh.  Instead you can calculate a new mesh.  Theres a CalculateFacets method that can be used instead, but when I was testing it, it's failing to, which is a bug.  However, there is also a CalculateFacetsWithOptions method and that is working.  Here's the modified version of the function.

 

Public Function TightRangeBox(Body As Inventor.SurfaceBody) As Inventor.Box
    ' Calculate a new mesh.
    Dim vertexCount As Long
    Dim facetCount As Long
    Dim vertexCoords() As Double
    Dim normalVectors() As Double
    Dim vertexIndices() As Long
    Dim options As NameValueMap
    Set options = ThisApplication.TransientObjects.CreateNameValueMap
    Call Body.CalculateFacetsWithOptions(0.005, options, vertexCount, facetCount, vertexCoords, normalVectors, vertexIndices)
    'Call Body.CalculateFacets(0.005, vertexCount, facetCount, vertexCoords, normalVectors, vertexIndices)
    
    ' Loop through the vertices and build up the range box.
    Dim minX As Double
    Dim maxX As Double
    Dim minY As Double
    Dim maxY As Double
    Dim minZ As Double
    Dim maxZ As Double
    minX = vertexCoords(0)
    maxX = vertexCoords(0)
    minY = vertexCoords(1)
    maxY = vertexCoords(1)
    minZ = vertexCoords(2)
    maxZ = vertexCoords(2)
    Dim i As Integer
    For i = 1 To vertexCount - 1
        If vertexCoords(i * 3) < minX Then
            minX = vertexCoords(i * 3)
        End If
        
        If vertexCoords(i * 3) > maxX Then
            maxX = vertexCoords(i * 3)
        End If
    
        If vertexCoords(i * 3 + 1) < minY Then
            minY = vertexCoords(i * 3 + 1)
        End If
        
        If vertexCoords(i * 3 + 1) > maxY Then
            maxY = vertexCoords(i * 3 + 1)
        End If
    
        If vertexCoords(i * 3 + 2) < minZ Then
            minZ = vertexCoords(i * 3 + 2)
        End If
        
        If vertexCoords(i * 3 + 2) > maxZ Then
            maxZ = vertexCoords(i * 3 + 2)
        End If
    Next
    
    Dim newBox As Box
    Set newBox = ThisApplication.TransientGeometry.CreateBox()
    newBox.MinPoint = ThisApplication.TransientGeometry.CreatePoint(minX, minY, minZ)
    newBox.MaxPoint = ThisApplication.TransientGeometry.CreatePoint(maxX, maxY, maxZ)
    
    Set TightRangeBox = newBox
End Function

Brian Ekins
Inventor and Fusion 360 API Expert
Mod the Machine blog
Message 9 of 9

nmunro
Collaborator
Collaborator

Hi Brian,

 

Great. I did think that might be the approach. I'll have to work around it for pre 2017 support but that is OK. Thanks again for the great support.

 

Neil

 

        


https://c3mcad.com

0 Likes