Hello,
I need to measure the angle of a toric face. The face is not generated by an Inventor function, so I can't get sketch or function properties.
I thought meaure the angle between the 2 extrem faces (or the angle between the normal vectors). But, how can I be sure to measure the right angle, and not the complementary angle ?
Right angle :
Wrong angle :
I found a method, quite complex :
-get the CentrePoint of each extrem face (supposing extremities edges are circular)
-get Point on face :
-Translate intermediate point from the Minor radius, in the right direction, so it is on the axis :
Create an ArcbyThreePoints then get its length :
This is how I would solve it:
Each face object has a Geometry object. Suppose your end faces are of type PlanarSurface (meaning the face is a plane), which it is in this case. Then the geometry of this face is a plane. A plane has a few properties: a Normal vector and a rootpoint. the angle between these faces can be computed as follows:
Dim oStartFace as Face
Dim oEndFace as Face
Dim oTorusFace as Face
Dim vAxisDir as UnitVector
set vAxisDir = oTorusFace.geometry.AxisDirection
'do note it is not known if dAngle is right angle or the wrong one
Dim dAngle as double
Dim PI as double
PI = math.atn(1)*4
' this routine will crash if either oStartFace or oEndFace are not PlanarSurfaces
'PI-angle because the normals are used to compute the angle,
'from the torus speaking, these are the tangential vectors.
dAngle = PI - oStartFace.Geometry.Normal.AngleTo(oEndFace.Geometry.Normal)
dAngle = dAngle/PI*180 'convert to degrees.
'if this cross product is in the same direction as the axisvector, the angle is the closest one.
Dim vCross as UnitVector
set vCross = oStartFace.geometry.normal.crossproduct(oEndFace.geometry.normal)
if vCross.dotproduct(vAxisDir ) < 0 then
dAngle = 360 - dAngle
end if
The function Unitvector.AngleTo(Unitvector) always computes the smallest angle between vectors. To find if the computed angle is in the right direction, we need to compare the crossproduct of the angles with axisdirection. A torus is if im correct always defined using the right hand rule from the axisdirection. A crossproduct also defines a 3rd vector perpendicular to both in the right hand rule direction. if these 2 dont match up, the angle between the vectors should be flipped. Short side note, as I use the normal vectors to compute the angle and the crossproduct, this logic might be inverted (so if the crossproduct is in the same direction as the axisdirection, flip the angle).
The sample code I included has been written straight out of my head, so it might have some naming issues. But this method is definitely cleaner and much faster than using a sketch.
Very curious how this works, and happy to help polishing it a bit if required. Hope this helped,
Peter
Hello Peter,
Your method is very interesting, and as you say "is definitely cleaner and much faster than using a sketch." (even if I don't really use a sketch, bu transcient geometry ^^).
But...
The torus is not created from Inventor, so I can't understand how it can be oriented ? I only have 3 faces : torus, start and end faces. Start.crossproduct(End) and End.crossproduct(start) are effectively colinear to torus.geometry.axisvector, but End could be Start, and Start could be End. So I don't know if cross product have to be in the same or reverse direction from Axis. Did I miss something ?
I join a test file, code is inside. If I reverse oFaceStart and oFaceEnd, cross product is reversed, and so the angle… but how can I know which is oFaceStart and wich is oFaceEnd ?
Alain
Hi @TONELLAL
How about this approach?
Dim oBody As SurfaceBody = ThisDoc.Document.ComponentDefinition.SurfaceBodies(1) 'Get the torus geometry Dim oTorus As Torus = oBody.Faces.OfType(Of Face).Where(Function(x As Face) TypeOf (x.Geometry) Is Torus)(0).Geometry 'Get the end faces Dim pFaces As IEnumerable(Of Face) = oBody.Faces.OfType(Of Face).Where(Function(x As Face) TypeOf (x.Geometry) Is Inventor.Plane) Dim oFace1 As Face = pFaces(0) Dim oFace2 As Face = pFaces(1) 'Get vectors from torus centerpoint to the faces Dim oVector1 As Vector = oTorus.CenterPoint.VectorTo(oFace1.GetClosestPointTo(oTorus.CenterPoint)) Dim oVector2 As Vector = oTorus.CenterPoint.VectorTo(oFace2.GetClosestPointTo(oTorus.CenterPoint)) 'Get smallest angle between these vectors Dim oAngle As Double = oVector1.AngleTo(oVector2) 'Get direction of vectors between these vectors oVector1.AddVector(oVector2) 'See if a ray in the direction of this vector, starting from the centerpoint, intersects the body Dim objects As ObjectsEnumerator Dim pts As ObjectsEnumerator oBody.FindUsingRay(oTorus.CenterPoint, oVector1.AsUnitVector, 0, objects, pts, True) 'If it does, flip the angle If pts.Count = 0 Then oAngle = Abs(oAngle - 2 * Math.PI) 'Return the angle MsgBox(oAngle * (180/Math.PI))
Jhoel Forshav
Download my free Inventor Addin - Hole Projector
LinkedIn | Ideas | Contributions | Blog posts | Website
Your approach is very clean, the only thing that needs to change is this line:
'If it does, flip the angle
If pts.Count = 0 Then oAngle = Abs(oAngle - 2*Math.PI)
We need 2*Pi instead of a single Pi or else it gives the opposite angle less 180°
Also, @TONELLAL , the code will fail if the angle is 180°, so if that is a possibility then you will want to add a check for that condition. I added a check to @JhoelForshav 's code:
Dim oBody As SurfaceBody = ThisDoc.Document.ComponentDefinition.SurfaceBodies(1)
'Get the torus geometry
Dim oTorus As Torus = oBody.Faces.OfType(Of Face).Where(Function(x As Face) TypeOf (x.Geometry) Is Torus)(0).Geometry
'Get the end faces
Dim pFaces As IEnumerable(Of Face) = oBody.Faces.OfType(Of Face).Where(Function(x As Face) TypeOf (x.Geometry) Is Inventor.Plane)
Dim oFace1 As Face = pFaces(0)
Dim oFace2 As Face = pFaces(1)
'Get vectors from torus centerpoint to the faces
Dim oVector1 As Vector = oTorus.CenterPoint.VectorTo(oFace1.GetClosestPointTo(oTorus.CenterPoint))
Dim oVector2 As Vector = oTorus.CenterPoint.VectorTo(oFace2.GetClosestPointTo(oTorus.CenterPoint))
'Check for coplanar faces:
Dim oAngle As Double
Dim RefPlane1 As Plane = ThisApplication.TransientGeometry.CreatePlane(oFace1.Vertices.Item(1).Point, oVector1)
Dim RefPlane2 As Plane = ThisApplication.TransientGeometry.CreatePlane(oFace1.Vertices.Item(1).Point, oVector2)
If RefPlane2.IsCoplanarTo(RefPlane1) = True Then oAngle = Math.PI : GoTo 10
'Get smallest angle between these vectors
oAngle = oVector1.AngleTo(oVector2)
'Get direction of vectors between these vectors
oVector1.AddVector(oVector2)
'See if a ray in the direction of this vector, starting from the centerpoint, intersects the body
Dim objects As ObjectsEnumerator
Dim pts As ObjectsEnumerator
oBody.FindUsingRay(oTorus.CenterPoint, oVector1.AsUnitVector, 0, objects, pts, True)
'If it does, flip the angle
If pts.Count = 0 Then oAngle = Abs(oAngle - 2*Math.PI)
'Return the angle
10: MsgBox(oAngle * (180/Math.PI))
This is the first approach I've tested, but I didn't know FindUsingRay, so I've created the intermediate FarmostPoint in direction Vector1 + Vector 2 and translate it on the torus axis, then create a Transcient ArcBy3Points. Your method is simpler but need a test for 180°, the arc is more complex to create but directly have the "SweepAngle" property.
Waiting more details from @Anonymous , his approach is very interesting too but I don't understand how the torus can be oriented.
You must have copied my code almost immediatley after i posted it, because I edited it to subtract 2*PI within like 30 seconds 🙂
The check if it's 180 degrees can be done easily with If oVector1.IsParallelTo(oVector2). So the complete working code would look something like this 🙂
Dim oAngle As Double Dim oBody As SurfaceBody = ThisDoc.Document.ComponentDefinition.SurfaceBodies(1) 'Get the torus geometry Dim oTorus As Torus = oBody.Faces.OfType(Of Face).Where(Function(x As Face) TypeOf (x.Geometry) Is Torus)(0).Geometry 'Get the end faces Dim pFaces As IEnumerable(Of Face) = oBody.Faces.OfType(Of Face).Where(Function(x As Face) TypeOf (x.Geometry) Is Inventor.Plane) Dim oFace1 As Face = pFaces(0) Dim oFace2 As Face = pFaces(1) 'Get vectors from torus centerpoint to the faces Dim oVector1 As Vector = oTorus.CenterPoint.VectorTo(oFace1.GetClosestPointTo(oTorus.CenterPoint)) Dim oVector2 As Vector = oTorus.CenterPoint.VectorTo(oFace2.GetClosestPointTo(oTorus.CenterPoint)) If oVector1.IsParallelTo(oVector2) oAngle = Math.PI Else 'Get smallest angle between these vectors oAngle = oVector1.AngleTo(oVector2) 'Get direction of vectors between these vectors oVector1.AddVector(oVector2) 'See if a ray in the direction of this vector, starting from the centerpoint, intersects the body Dim objects As ObjectsEnumerator Dim pts As ObjectsEnumerator oBody.FindUsingRay(oTorus.CenterPoint, oVector1.AsUnitVector, 0, objects, pts, True) 'If it does, flip the angle If pts.Count = 0 Then oAngle = Abs(oAngle - 2 * Math.PI) 'Return the angle End If MsgBox(oAngle * (180/Math.PI))
Jhoel Forshav
Download my free Inventor Addin - Hole Projector
LinkedIn | Ideas | Contributions | Blog posts | Website
Ah yes I see that now haha. I haven't done many Vector API calls, so I didn't realize there was a "IsParallelTo" method for Vectors, but that is cleaner.
Yes, you are completely right on that regard. This entire statement only works if the start face defined in the code is actually the start face of said torus. However, if a face is created using features or imported as a solid body does not matter as we just need the faces.
This time I have fired up Inventor and worked out a working test code.
To determine which face is the start face another small vector trick should be used. Compose a new vector from the centerpoint of the torus to a point on the startface (lets suppose this point is the closest point to the center point). if the crossproduct between this vector and the axisvector is in the opposite direction as the normal of the startface, the startface is the actual start face. If not, flip the startface and the endface and compute the angle. I have altered the code quite a bit, but from the short tests I made, it proofed correct result every time:
Function GetTorusSweepAngle(oTorusFace As Face, oStartFace As Face, oEndFace As Face) As Double
Dim vCenterStart As Vector
Dim vCenterEnd As Vector
Dim vAxisDir As UnitVector
Set vAxisDir = oTorusFace.Geometry.AxisVector
Dim dAngle As Double
Dim PI As Double
PI = Math.Atn(1) * 4
Dim oCenterPoint As Point
Set oCenterPoint = oTorusFace.Geometry.CenterPoint
Set vCenterStart = oCenterPoint.VectorTo(oStartFace.GetClosestPointTo(oCenterPoint))
Set vCenterEnd = oCenterPoint.VectorTo(oEndFace.GetClosestPointTo(oCenterPoint))
'short note, if Face.isParamReversed = true, then the normal vector should be flipped 180 degrees
Dim vNormalStart As Vector
Set vNormalStart = oStartFace.Geometry.Normal.AsVector
If oStartFace.IsParamReversed Then
Call vNormalStart.ScaleBy(-1)
End If
If vCenterStart.CrossProduct(vAxisDir.AsVector).DotProduct(vNormalStart) > 0 Then
'switch start with end
Dim vDumpVector As Vector
Set vDumpVector = vCenterStart
Set vCenterStart = vCenterEnd
Set vCenterEnd = vDumpVector
End If
If vCenterStart.IsParallelTo(vCenterEnd) Then
dAngle = 180
GetTorusSweepAngle = dAngle
Exit Function
End If
'Instead of using the normal vectors, actually using the proper vectors
'might be a bit smarter :)
dAngle = vCenterStart.AngleTo(vCenterEnd)
dAngle = dAngle / PI * 180 'convert to degrees.
'I first thought that if they are in opposite direction, the angle
'should be flipped, but fun fact: no.
Dim vCross As Vector
Set vCross = vCenterStart.CrossProduct(vCenterEnd)
If vCross.DotProduct(vAxisDir.AsVector) > 0 Then
dAngle = 360 - dAngle
End If
GetTorusSweepAngle = dAngle
End Function
The important note is to check the Face.isParamReversed property. if that is true, the normal vector is pointing into the body (so in the wrong direction). Also, if you want to have this procedure a tad faster, using getClosestPointTo() is from my experience relatively a slow procedure, using the center point of the edge of both faces is faster, but makes the code a bit larger. I tested this function with torus angles of 60, 120 and 320 degrees using and flipping the start / end faces in the arguments, it all returned the correct answer.
Also good to see you used transientgeometry, because then you are pretty much just as fast and clean (with clean i do not really mean clean code, but just that you dont leave anything in the model when you run it).
All of this is very interesting ! I now have several methods and better understand how it works.
But there is a limitation for these methods : extrem edges of the torus must be circular. Or, at least, must have a center (in this case I'd consider that the torus length is the length between centers). What about a torus with notched ends, like this one :
The length should be the length of the "range torus". Tn this case, I need to get the Farmostpoint, but the direction should be a "circular vector", instead of a usual unit vector :
On a planar edge :
In the case of a torus :
I tried several approaches, but nothing very clear :
Once we have the plane curve, it is possible to obtain the farmost point (here at the left in yellow), then get back the corresponding parameter and use it to get the point on the edge using oEdge.Evaluator.GetPointatParam.
On planar curve, derivative (or second derivative) can be used for slope (or curvature. So I suppose it can be used on 3D curves too... But math classes are far away ^^
Hi @TONELLAL
I stumbled across this thread again now, almost 3 years later, because I needed pretty much the exaxt same thing for a project I'm working on 🙂
This is the way I solved it for myself using the surface evaluator of the torus face.
Sub Main Dim oFace As Face = ThisApplication.CommandManager.Pick(kPartFaceFilter, "Select torus Face") If oFace Is Nothing Then Exit Sub Dim torusAngle = GetTorusAngle(oFace) If torusAngle IsNot Nothing Then MsgBox("The sweep angle of the torus segment is " & Math.Round(torusAngle, 2, MidpointRounding.AwayFromZero) & " deg") End If End Sub Function GetTorusAngle(oFace As Face) Dim oTorus As Torus = TryCast(oFace.Geometry, Torus) If oTorus Is Nothing Then MsgBox("The selected face geometry is not of type Torus.") Return Nothing End If Dim oEval As SurfaceEvaluator = oFace.Evaluator Dim pRange As Box2d = oEval.ParamRangeRect Dim startPoint2d As Point2d = pRange.MinPoint Dim endPoint2d As Point2d = pRange.MaxPoint Dim oTG As TransientGeometry = ThisApplication.TransientGeometry Dim oCurve2d As LineSegment2d = oTG.CreateLineSegment2d(startPoint2d, endPoint2d) Dim oCurve3d As BSplineCurve = oEval.Get3dCurveFrom2dCurve(oCurve2d) Dim startPointArr() As Double = {0, 0, 0 } Dim endPointArr() As Double = {0, 0, 0 } oCurve3d.Evaluator.GetEndPoints(startPointArr, endPointArr) Dim startPoint3d As Point = oTG.CreatePoint(startPointArr(0), startPointArr(1), startPointArr(2)) Dim endPoint3d As Point = oTG.CreatePoint(endPointArr(0), endPointArr(1), endPointArr(2)) Dim centerPoint As Point = oTorus.CenterPoint Dim axisVector As Vector = oTorus.AxisVector.AsVector Dim oPlane As Plane = oTG.CreatePlane(centerPoint, axisVector) Dim projVector1 As Vector = axisVector.Copy Dim projVector2 As Vector = axisVector.Copy projVector1.ScaleBy(oPlane.DistanceTo(startPoint3d) * -1) projVector2.ScaleBy(oPlane.DistanceTo(endPoint3d) * -1) startPoint3d.TranslateBy(projVector1) endPoint3d.TranslateBy(projVector2) Dim v1 As Vector = centerPoint.VectorTo(startPoint3d) Dim v2 As Vector = centerPoint.VectorTo(endPoint3d) Return v1.AngleTo(v2) * 180 / Math.PI End Function
Jhoel Forshav
Download my free Inventor Addin - Hole Projector
LinkedIn | Ideas | Contributions | Blog posts | Website
Thank you for you feedback !
But I don't understand what is ParamRangeRect...
The angle I obtain is this one, which is the complement of the torus angle :
Good catch @TONELLAL !
I never tried it for angles greater than 180 degrees...
I figured out a way to create a curve that doesn't go from corner to corner of the "unfolded surface", but instead just straight across with a constant X-value. This then results in an Arc3d when we wrap it back around the surface. From there we can just get the Arc3d.SweepAngle.
Sub Main Dim oFace As Face = ThisApplication.CommandManager.Pick(kPartFaceFilter, "Select torus Face") If oFace Is Nothing Then Exit Sub Dim oTorus As Torus = TryCast(oFace.Geometry, Torus) If oTorus Is Nothing Then MsgBox("The selected face geometry is not of type Torus.") Exit Sub End If MsgBox("The sweep angle of the torus segment is " & Math.Round(GetTorusAngle(oFace), 2, MidpointRounding.AwayFromZero) & " deg") End Sub Function GetTorusAngle(oFace As Face) Dim oEval As SurfaceEvaluator = oFace.Evaluator Dim pRange As Box2d = oEval.ParamRangeRect Dim startPoint2d As Point2d = pRange.MinPoint Dim endPoint2d As Point2d = pRange.MaxPoint Dim oTG As TransientGeometry = ThisApplication.TransientGeometry Dim oCurve2d As LineSegment2d oCurve2d = oTG.CreateLineSegment2d(startPoint2d, oTG.CreatePoint2d(startPoint2d.X, endPoint2d.Y)) Dim oCurve3d As Arc3d = oEval.Get3dCurveFrom2dCurve(oCurve2d) Return oCurve3d.SweepAngle * 180 / Math.PI End Function
Jhoel Forshav
Download my free Inventor Addin - Hole Projector
LinkedIn | Ideas | Contributions | Blog posts | Website
Can't find what you're looking for? Ask the community or share your knowledge.