Get point on a curve in CATIA V5 VBA


To create a point on a curve in CATIA V5 is a pretty simple task. Things get complicated if we need to repeat it in VBA. Although most of the information you need you can find also in CATIA V5 documentation, the lack of examples is a real problem. I would like to try to fill this gap and show you some of the functions you can use when you work with CATIA curves. And because I like when things are moving, we create an animation :).


Wanna see it in action?

Then watch this video:
Get point on a curve in a CATIA V5 Drawing (VBA)

Or a more crazy version with multiple elements:
Get points on a curve in a CATIA V5 Drawing (VBA)

A Timer procedure

Since we are going to create a simple animation, we need a timer. Native VBA time-related functions only provide up to seconds accuracy. However, for our animation, we need a higher resolution, ideally milliseconds resolutions.

The Windows API provides several ways to measure elapsed time, the simplest is perhaps the GetTickCount function. This function measures the number of milliseconds that have elapsed since the system was started, up to 49.7 days. According to official Microsoft documentation, the resolution of the GetTickCount function is limited to the resolution of the system timer, which is typically in the range of 10 milliseconds to 16 milliseconds. For more details about this function look here.

The GetTickCount function together with Sleep and DoEvents function provides a good enough ticker for most of the applications. Running them within a loop, we get a simple timer that provides a higher resolution than native VBA and it is not blocking a CATIA user interface. But keep in mind, every computer is different and maybe you need to adjust TIMER_INTERVAL constant or a Sleep parameter (both in milliseconds) if your system is too slow, too fast or nonresponding.


Option Explicit

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function GetTickCount Lib "kernel32.dll" () As Long

Private myStep As Long
Private counter As Long
Private myShape As Circle2D

Private Const TIMER_INTERVAL As Long = 50
Private Const NUMBER_OF_POINTS As Long = 200

Sub Main()
    ' get an active view
    Dim myView As DrawingView
    Set myView = CATIA.ActiveDocument.Sheets.ActiveSheet.Views.ActiveView
    
    ' get a curve, first element is axis system
    Dim myCurve
    Set myCurve = myView.GeometricElements.Item(2)
    
    Dim startTime As Long
    startTime = GetTickCount

    myStep = 1
    
    ' main timer loop
    Do
        If (GetTickCount - startTime) > TIMER_INTERVAL Then
            ' draw circle
            Draw myView, myCurve
            
            'reset time after redrawing
            startTime = GetTickCount
        End If
        
        ' pause execution
        Sleep 5
        
        ' process events (do not block UI)
        DoEvents
    Loop While True
End Sub
    

A Draw procedure

A Draw procedure takes care of rendering of a moving element(s), circle(s). It is called on every timer tick, it calculates the next point on the curve and draws/redraws a circle in that point. At first, we split the curve into a number of points defined by NUMBER_OF_POINTS constant. On every call of the function, we increase a counter variable and we get the next point from the predefined number of points on the curve.

With a function GetParamExtents we get parametric extents of a curve, which is a parametric equivalent of the end-points. The return value is an array where the first element is the parameter associated with the start point of the curve and the second one is the parameter associated with the end point of the curve.

To get a point lying on a curve we use the function GetPointAtParam. This function returns a point on the curve computed from an input parameter. If the input parameter is a value (Double) within the range defined by parametric extents, as a result, we get a location of the 2D point on the curve in a form of an array with X and Y coordinates of the computed point. A variable param is incrementally increased/decreased on every function call moving constantly between the start point of the curve and the end point.

Finally, we create a circle in the computed point on the curve and we assign it to a module variable myShape. The circle is created only on a first call of the function, on the other calls we just modify the position of the existing one. In the last lines, we control a direction of the movement with a variable myStep, which switches from positive to negative and vice versa when we get outside of the range of the total number of points (when we reach either the start point of the curve or the end point). In the end we increase/decrease the counter variable.


Sub Draw(myView As DrawingView, myCurve)
    Dim distanceRatio As Double
    distanceRatio = 1 / NUMBER_OF_POINTS * counter
    
    Dim paramExtents(1)
    myCurve.GetParamExtents paramExtents
    
    Dim param As Double
    param = paramExtents(0) + (paramExtents(1) - paramExtents(0)) * distanceRatio
    
    Dim currPoint(1)
    myCurve.GetPointAtParam param, currPoint
    
    Dim fact2D
    Set fact2D = myView.Factory2D
    
    If myShape Is Nothing Then
        Set myShape = fact2D.CreateClosedCircle(currPoint(0), currPoint(1), 5)
    Else
        myShape.SetData currPoint(0), currPoint(1), 5
    End If
    
    If counter < 0 Or counter > NUMBER_OF_POINTS Then myStep = -myStep
    counter = counter + myStep
End Sub
    

To test it, create and activate a view with the curve as the only element inside. Then copy a source code into a standard module and launch the Main procedure.

A complete source can be found here Point on a curve source
A more crazy version with multiple moving elements Points on a curve source



Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>