Community
Inventor Programming - iLogic, Macros, AddIns & Apprentice
Inventor iLogic, Macros, AddIns & Apprentice Forum. Share your knowledge, ask questions, and explore popular Inventor topics related to programming, creating add-ins, macros, working with the API or creating iLogic tools.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Measure an angle by API

14 REPLIES 14
Reply
Message 1 of 15
TONELLAL
1592 Views, 14 Replies

Measure an angle by API

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 ?

14 REPLIES 14
Message 2 of 15
Anonymous
in reply to: TONELLAL

Can you show us exactly which angle you which to measure? perhaps a picture?

Message 3 of 15
TONELLAL
in reply to: Anonymous

Right angle :

Right angleRight angle

 

Wrong angle :

Wrong angleWrong angle

 

I found a method, quite complex :

-get the CentrePoint of each extrem face (supposing extremities edges are circular)

-get Point on face :

2020-09-16_15h29_15.png

 

-Translate intermediate point from the Minor radius, in the right direction, so it is on the axis :

2020-09-16_15h36_03.png

 

Create an ArcbyThreePoints then get its length :

2020-09-16_15h39_04.png

 

Message 4 of 15
Anonymous
in reply to: TONELLAL

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

Message 5 of 15
TONELLAL
in reply to: Anonymous

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

Message 6 of 15
JhoelForshav
in reply to: TONELLAL

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))
Message 7 of 15
J-Camper
in reply to: JhoelForshav

@JhoelForshav,

 

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))

 

Message 8 of 15
TONELLAL
in reply to: J-Camper

@J-Camper @JhoelForshav :

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.

Message 9 of 15
JhoelForshav
in reply to: TONELLAL

@J-Camper 

You must have copied my code almost immediatley after i posted it, because I edited it to subtract 2*PI within like 30 seconds 🙂

 

@TONELLAL 

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))

 

Message 10 of 15
J-Camper
in reply to: JhoelForshav

@JhoelForshav

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.

Message 11 of 15
Anonymous
in reply to: TONELLAL

@TONELLAL 

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).

 

Message 12 of 15
TONELLAL
in reply to: Anonymous

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 :

2020-09-18_13h55_56.png

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 :

2020-09-21_18h23_07.png

In the case of a torus :

2020-09-21_18h32_43.png

 

 

I tried several approaches, but nothing very clear :

  • Get points on the edge, with Edge.Evaluator.GetPointAtParam(params, points). It seems there is always a point at the farmost point, but I don't understand why this should be always true :

2020-09-21_20h52_45.png

2020-09-21_20h54_28.png

 

  • Use these points to calculate "unfold edge", by a spline define like this (in transient geometry) :

2020-09-22_14h04_01.png

 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.

  

  • Use oEge.GetFirstDerivative

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 ^^

 

  • Get the BoudingBox of the edge, then use vectors by (torus center, Boundingbox center). This is the easiest way, but also the most approximative : 

2020-09-22_14h18_42.png

 

 

Message 13 of 15
JhoelForshav
in reply to: TONELLAL

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

 

Message 14 of 15
TONELLAL
in reply to: JhoelForshav

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 :

 

TONELLAL_0-1683202138327.png

 

Message 15 of 15
JhoelForshav
in reply to: TONELLAL

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

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report