Convert NURBS curve to Arc curve

Convert NURBS curve to Arc curve

miminguyenps1098
Participant Participant
2,614 Views
14 Replies
Message 1 of 15

Convert NURBS curve to Arc curve

miminguyenps1098
Participant
Participant

Hello everyone. I am working on a 3D object in Fusion 360 and in that 3D object has so many NURBS curves so I want to convert the NURBS curve to any curve (example Arc curve). My purpose is to measure important parameters for example the radius of an arc curve. Is there any way to do that using API? I am just a newbie in Fusion API, I would really appreciate it if someone help me.

 

Thank you and wish you have a nice day!

 

0 Likes
Accepted solutions (2)
2,615 Views
14 Replies
Replies (14)
Message 2 of 15

kandennti
Mentor
Mentor

Hi @miminguyenps1098 .

 

If a spline arc approximation is OK, I created it about 4 years ago.

# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core

# arc-approximation tolerance - Unit is Cm
tolerance = 0.001

def run(context):
    ui = adsk.core.UserInterface.cast(None)
    try:
        app: adsk.core.Application = adsk.core.Application.get()
        ui = app.userInterface

        # 面選択
        msg: str = 'Select curve/ESC-abort'
        selFilter: str = 'SketchCurves'
        sel: adsk.core.Selection = selectEnt(msg, selFilter)
        if not sel:
            return
        crv = sel.entity

        # 点群
        points = initPointsOnCurve(crv.geometry, tolerance)

        # 円弧近似
        threeArcs = []
        threeArcs = initThreePointArc(0, len(points)-1, tolerance, points, threeArcs)

        if len(threeArcs) < 1:
            ui.messageBox('Could not approximate the arc.')
            return

        # スケッチ作成
        des = adsk.fusion.Design.cast(app.activeProduct)
        comp = des.rootComponent
        skt: adsk.fusion.Sketch = comp.sketches.add(comp.xYConstructionPlane)
        skt.name = "ArcApproximation"

        # 円弧作成
        skt_arcs = skt.sketchCurves.sketchArcs
        skt.isComputeDeferred = True
        [skt_arcs.addByThreePoints(p1,p2,p3) for (p1,p2,p3) in threeArcs]
        skt.isComputeDeferred = False

        ui.messageBox(f'{len(threeArcs)} arc created')

    except:
        if ui:
           ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

# 外心円
def getCircumCircleOFTraiangle(p1,p2,p3):
    # 3点ベクトル取得
    vec1_2 = adsk.core.Vector3D.cast(p2.asVector())
    vec1_2.subtract(p1.asVector())
    vec1_2.normalize()

    vec2_3 = adsk.core.Vector3D.cast(p3.asVector())
    vec2_3.subtract(p2.asVector())
    vec2_3.normalize()

    # 平行チェック
    if vec1_2.isParallelTo(vec2_3):
        return None

    # P2_P3間 オイラー線
    eulerLine = vec2_3.crossProduct(vec1_2.crossProduct(vec2_3))
    eulerLine.normalize()

    # 中間点
    p1_2 = getMidPoint3D(p1,p2)
    p2_3 = getMidPoint3D(p2,p3)

    # 不明
    nv = vec1_2.dotProduct(eulerLine)
    t = (vec1_2.dotProduct(p1_2.asVector()) - vec1_2.dotProduct(p2_3.asVector())) / nv

    # 外心
    center = getCircumCenter(p2_3,eulerLine,t)

    # 半径
    radius = center.distanceTo(p1)

    return (center, radius)
    
# 外心
def getCircumCenter(p,v,l):
    pos = (p.x + v.x * l,
           p.y + v.y * l,
           p.z + v.z * l)
    return adsk.core.Point3D.create(pos[0],pos[1],pos[2])

# 中間点
def getMidPoint3D(p1,p2):
    pos = ((p1.x + p2.x) * 0.5,
           (p1.y + p2.y) * 0.5,
           (p1.z + p2.z) * 0.5)
    return adsk.core.Point3D.create(pos[0],pos[1],pos[2])

def isInTolerance(center, radius, tol, points):
    dist_lst = [radius - center.distanceTo(p) for p in points]
    res = [d for d in dist_lst if d > tol]
    
    return True if len(res) < 1 else False

# 3点円弧 再帰
def initThreePointArc(startIdx, endIdx, tol, points, threeArcs):
    
    if 2 > (endIdx - startIdx):
        return threeArcs

    # 中間idx
    midIdx = int((startIdx + endIdx) * 0.5)
    arc = getCircumCircleOFTraiangle(
        points[startIdx],
        points[midIdx], 
        points[endIdx]
    )

    if arc is None:
        return threeArcs

    # 円弧評価
    if isInTolerance(arc[0], arc[1], 0.001, points[startIdx+1:endIdx-1]):
        threeArcs.append([points[startIdx],points[midIdx],points[endIdx]])
    else:
        threeArcs = initThreePointArc(startIdx, midIdx, tol, points, threeArcs)
        threeArcs = initThreePointArc(midIdx, endIdx, tol, points, threeArcs)
        
    return threeArcs

# トレランス以内の曲線上の点群
def initPointsOnCurve(geo, tol):
    # evaluator
    eva = geo.evaluator
    
    # 始点終点
    _, startPoint, endPoint = eva.getEndPoints()
    _, startPram = eva.getParameterAtPoint(startPoint)
    _, endPram = eva.getParameterAtPoint(endPoint)
    
    # トレランス以内の点群
    _, pnts = eva.getStrokes(startPram, endPram, tol)
    return pnts

# 選択
def selectEnt(
        msg: str,
        filterStr: str) -> adsk.core.Selection:

    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        sel = ui.selectEntity(msg, filterStr)
        return sel
    except:
        return None
Message 3 of 15

miminguyenps1098
Participant
Participant

Thank you so much for your reply, I appreciate it. But I think that is not the thing I want. 

0 Likes
Message 4 of 15

kandennti
Mentor
Mentor

@miminguyenps1098 .

 

Are you saying that you want to make a circular arc because originally one arc is a NURBS curve?

0 Likes
Message 5 of 15

kandennti
Mentor
Mentor

@miminguyenps1098 .

 

Attached is a NurbsCurve created from an arc.
Do you mean something like this?

 

If different, please attach a sample f3d file.

0 Likes
Message 6 of 15

miminguyenps1098
Participant
Participant

Thank you for your reply.

For example, I want to measure the radius of all arc curves (in the b-rep edge there is 7 type of curve). But when I use API to print the type of edge in each face of the object, I see that the most type of curve in an object is the NURBS curve type (with degrees 3 or 5). But with the NURBS curve type, I can not determine the radius or anything about that curve. So I want to know if there is any way to convert the NURBS curve to an arc or circle curve,... so I can measure the radius. 

 

 

0 Likes
Message 7 of 15

kandennti
Mentor
Mentor

@miminguyenps1098 .

 

I do not understand English. Therefore, I cannot understand what you want even if you explain it only in words.

I told you beforehand to attach a sample f3d file if the f3d file I attached is different, but unfortunately you did not get the message.
I am not likely to be able to lend a hand.

0 Likes
Message 8 of 15

miminguyenps1098
Participant
Participant

Yeah, I mean something like this. I hope you can help me!

0 Likes
Message 9 of 15

kandennti
Mentor
Mentor
Accepted solution

@miminguyenps1098 .

 

The CurveEvaluator3D object can be used to evaluate curves.

https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-GUID-dc7ae251-e060-4d87-b6b8-e7f78abc0777 

 

I made a sample.
It examines the curvature at numerous positions on the curve, determines that if it is a constant value, it is an arc, and obtains the three points required for an arc.

# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core

def run(context):
    ui = adsk.core.UserInterface.cast(None)
    try:
        app: adsk.core.Application = adsk.core.Application.get()
        ui = app.userInterface

        # select curve
        msg: str = 'Select Sketch Curve'
        selFilter: str = 'SketchCurves'
        sel: adsk.core.Selection = selectEnt(msg, selFilter)
        if not sel:
            return
        sktCrv: adsk.fusion.SketchCurve = sel.entity

        # get ArcThreePoints
        pnts = nurbs2ArcThreePoints(
            sktCrv
        )

        if len(pnts) < 3:
            ui.messageBox('Cannot be converted to a Arc')
            return

        # create Sketch
        refSkt: adsk.fusion.Sketch = sktCrv.parentSketch
        comp: adsk.fusion.Component = refSkt.parentComponent
        skt: adsk.fusion.Sketch = comp.sketches.add(
            refSkt.referencePlane
        )
        skt.name = 'Nurbs2Arc'

        # create Arc
        skt.sketchCurves.sketchArcs.addByThreePoints(
            pnts[0],
            pnts[1],
            pnts[2],
        )

        ui.messageBox('Done')

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

# return [Point3D,Point3D,Point3D]
def nurbs2ArcThreePoints(
    sktCrv: adsk.fusion.SketchCurve,
    tolerance: float = 0.001) -> list:

    # line NG
    if sktCrv.classType() == adsk.fusion.SketchLine.classType():
        return []

    # geometry
    geo = sktCrv.geometry

    # evaluator
    eva: adsk.core.CurveEvaluator3D = geo.evaluator

    # get Points On Curve
    _, startPoint, endPoint = eva.getEndPoints()
    _, startPrm = eva.getParameterAtPoint(startPoint)
    _, endPrm = eva.getParameterAtPoint(endPoint)
    _, pnts = eva.getStrokes(startPrm, endPrm, tolerance)

    # get Parameters
    _, prms = eva.getParametersAtPoints(pnts)

    # get Curvatures
    _, _, curvatures = eva.getCurvatures(prms)
    curvatures = [round(v/tolerance)*tolerance for v in curvatures]

    # Convertible or Evaluatable
    if len(set(curvatures)) != 1:
        return []

    # Three points for Arc
    return [
        pnts[0],
        pnts[len(pnts) // 2],
        pnts[-1]
    ]


def selectEnt(
        msg: str,
        filterStr: str) -> adsk.core.Selection:

    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        sel = ui.selectEntity(msg, filterStr)
        return sel
    except:
        return None
Message 10 of 15

miminguyenps1098
Participant
Participant

Thank you so much, I think this is really helpful for me. But when I draw a sketch line with degree 3 or 5, this code can not convert. I really appreciate it if you have any documents about the NURBS curve in degrees 3 or 5 and you can share them with everyone here.

Once again, thank you so much, and hope you have a great day!

Message 11 of 15

miminguyenps1098
Participant
Participant

Hi kandennti,

I have seen your code and I have a problem with the units, can you explain what is the units of curvature? 

Thank you!

0 Likes
Message 13 of 15

miminguyenps1098
Participant
Participant

Thank you so much!

Message 14 of 15

BrianEkins
Mentor
Mentor
Accepted solution

I'm a little late to the party, but hopefully, this will help. The script below prompts you to select a sketch curve. It uses the curve and the point you selected it at and compute the radius at the point and draws a line to the center of the radius of the curve at that location. It will work with any sketch curve, except for a line because it has infinite curvature.

 

Here's a picture after using the script on some test sketches.

 

Curvature.png

 

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui = app.userInterface        
        
        design = adsk.fusion.Design.cast(app.activeProduct)
        root = design.rootComponent

        cg = root.customGraphicsGroups.add()
        while True:
            try:
                skCurveSel = ui.selectEntity('Select a curve.', 'SketchCurves')
            except:
                cg.deleteMe()
                app.activeViewport.refresh()
                return

            skCurve = skCurveSel.entity
            worldGeom = skCurve.worldGeometry

            eval = worldGeom.evaluator
            (_, param) = eval.getParameterAtPoint(skCurveSel.point)
            direction: adsk.core.Vector3D
            (_, direction, curvature) = eval.getCurvature(param)

            radius = 1/curvature
            app.log(f'Curvature: {curvature}, Radius: {radius} cm')

            pnt1 = skCurveSel.point
            pnt2 = pnt1.copy()
            direction.normalize()
            direction.scaleBy(radius)
            pnt1.translateBy(direction)
            
            coords = list(pnt1.asArray())
            coords.extend(list(pnt2.asArray()))
            cgCoords = adsk.fusion.CustomGraphicsCoordinates.create(coords)
            cg.addLines(cgCoords, [], False)

            app.activeViewport.refresh()
    except:
        if cg:
            cg.deleteMe()
            app.activeViewport.refresh()

        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 15 of 15

miminguyenps1098
Participant
Participant

Thank you so much, it's very helpful for me!

0 Likes