Problem of Control Point Splines in using Sketch.findConnectedCurves

Problem of Control Point Splines in using Sketch.findConnectedCurves

nnikbin
Collaborator Collaborator
1,574 Views
15 Replies
Message 1 of 16

Problem of Control Point Splines in using Sketch.findConnectedCurves

nnikbin
Collaborator
Collaborator

We already know that according to @marshaltu , Unfortunately the tangent handle line is treated as a real curve in Fusion 360.

 

It is not a big problem because we can hide them by getting them using SketchFittedSpline.getTangentHandle method, then deleting them using SketchFittedSpline.deleteMe method. We can also make them visible again using SketchFittedSpline.activateTangentHandle method.

 

But I think the problem with Control Point Splines is bigger. I was not able to find any API to hide control point handles and they make problems in using Sketch.findConnectedCurves method.

 

For example, for the following samples I used findConnectedCurves method to find the connected curves of each selected curve and printed the Object Type and Connected Curves Count for the selected curve and Object Type, Start Point and End Point of each curve in the returend ObjectCollection.

 

39.png

40.png

41.png

As you can see the control point handles make the output of findConnectedCurves method almost useless.

0 Likes
1,575 Views
15 Replies
Replies (15)
Message 2 of 16

nnikbin
Collaborator
Collaborator
0 Likes
Message 3 of 16

MichaelT_123
Advisor
Advisor

Hi Mr  NNikbin,

 

Yes, there is the conundrum here, as the fixedSpline handles are required to distinguish it from other curves, contributing to the outcome of findConnectedCurves method.

How to solve it?

I have not tried it but consider checking isDeletable attribute in the connectedCurvesCollection removing respective curves from it.

Perhaps TF360 might recognize it as the thing worthy to implement internally.

 

Regards

MichaelT

MichaelT
0 Likes
Message 4 of 16

kandennti
Mentor
Mentor

Hi @nnikbin .

 

We are still in the testing phase, but it looks like we can get it by using the TextCommands.

All you need is a sketch point for the control point?

0 Likes
Message 5 of 16

nnikbin
Collaborator
Collaborator

Thank you @MichaelT_123  for your reply,

The main problem is:

If there is a Control Point Spline in a sequence of connected curves, findConnectedCurves return a wrong list. For example in my 2nd and 3rd examples it returns just one curve instead of 2 or 4, because the algorithm for finding connected curves riches a branch (a real curve and a handle) and stops.

0 Likes
Message 6 of 16

nnikbin
Collaborator
Collaborator

Thank you @kandennti  for your reply.

 

Actually I just wanted to report the problem and I am not looking for a workaround using TextCommands because it is not critical for my add-ins. But if you find a solution probably it will help other developers who want their add-ins support this case.

Message 7 of 16

MichaelT_123
Advisor
Advisor

Hi Mr NNikbin,

Thus it seems that the case requires the inquisitive TF360 attention. As the alternative consider createPath( thisFixedSpline) option (not sure about the exact syntax ...)

Regards

MichaelT

MichaelT
Message 8 of 16

nnikbin
Collaborator
Collaborator

Thank you @MichaelT_123  for your interesting suggestion on using createPath. I tried it and unfortunately it has the same problem as findConnectedCurves.

0 Likes
Message 9 of 16

kandennti
Mentor
Mentor

@nnikbin .

 

As it is finished, I will leave it for those who want to use it in the future.

 

In the sample, first select the sketch curve.
It ends with a control point selected.

# Fusion360API Python script
import adsk.core, adsk.fusion, adsk.cam, traceback
import json

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

        # select Control Point Spline
        msg :str = 'Select'
        selFiltter :str = 'SketchCurves'
        sel :adsk.core.Selection = selectEnt(msg ,selFiltter)
        if not sel: return

        crv = sel.entity

        # get Control Points
        controlPoints = getControlPoints(crv)
        if len(controlPoints) < 1:
            ui.messageBox('Not a Control Point Spline.')
            return

        # select Control Points
        sels = ui.activeSelections
        [sels.add(p) for p in controlPoints]

        ui.messageBox('Done')

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

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

    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        sel = ui.selectEntity(msg, filtterStr)
        return sel
    except:
        return None

# Get the Control Point
# Returns an empty list, except for control point splines.
def getControlPoints(crv :adsk.fusion.SketchFittedSpline) -> list:
    app = adsk.core.Application.get()
    ui = app.userInterface
    sels = ui.activeSelections

    # --support functions--
    def getIdFromKey(entityId, key) -> int:
        prop = getPropertiesJson(entityId)

        return prop[key]['entityId']

    def getIdsFromKey(entityId, key) -> List:
        prop = getPropertiesJson(entityId)

        ids = []
        for idx in range(len(prop[key])):
            ids.append(prop[key][idx]['entityId'])

        return ids

    def getPropertiesJson(entityId) -> json:
        prop = app.executeTextCommand(u'PEntity.Properties {}'.format(entityId))
        return  json.loads(prop)

    def getSelectItemEntityId(entity) -> int:
        selectionsForcedClear()
        sels.add(entity)

        paths = app.executeTextCommand(u'Selections.List')
        id = paths.split(':')[-1].split('+')[0]

        selectionsForcedClear()

        return int(id)

    def getNextPointId(targetId, crvId, ids):
        childrenIds = getIdsFromKey(targetId, 'children')

        for id in childrenIds:
            geoIds = getIdsFromKey(id, 'geometries')
            for geoId in geoIds:
                if geoId == crvId:
                    continue

                sId = getIdFromKey(geoId, 'rStartPoint')
                if not sId in ids:
                    return sId

                eId = getIdFromKey(geoId, 'rEndPoint')
                if not eId in ids:
                    return eId

    def getEntityFromIds(ids) -> list:
        selectionsForcedClear()

        for id in ids:
            app.executeTextCommand(u'Selections.add {}'.format(id))

        lst = []
        for idx in range(sels.count):
            lst.append(sels[idx].entity)

        selectionsForcedClear()

        return lst

    def selectionsForcedClear():
        sels.clear()

        if sels.count > 0:
            ents = sels.all
            app.executeTextCommand(u'Commands.Start SelectabilityToggleCmd')
            [sels.add(ent) for ent in ents]
            app.executeTextCommand(u'Commands.Start SelectabilityToggleCmd')
            sels.clear()

    def isControlPointSpline(crv, prop) -> bool:
        if crv.objectType != 'adsk::fusion::SketchFittedSpline':
            return False

        if prop['intentionDegree'] != 5:
            return False
        
        return True
    # ----

    # get curve id
    crvId = getSelectItemEntityId(crv)
    prop = getPropertiesJson(crvId)

    # ControlPointSpline check
    if not isControlPointSpline(crv, prop):
        return []

    # get start/end point id
    startId = prop['rStartPoint']['entityId']
    endId = prop['rEndPoint']['entityId']

    # get Control Point Ids
    ids = [startId]
    while True:
        pass
        id = getNextPointId(ids[-1], crvId, ids)
        ids.append(id)
        if id == endId:
            break

    # get Control Points
    return getEntityFromIds(ids)

 

I am not sure if the Control Point Spline decision (isControlPointSpline) is correct, but I think it is.

 

0 Likes
Message 10 of 16

nnikbin
Collaborator
Collaborator

Thank you @kandennti  for taking the time to provide this interesting code.

 

It works fine for selecting control points of one curve (I imported List from typing module because I am using python 3.7.6 and without it line 60 throws an exception). But I did not know how I can use the selection of control points to hide the handles or make findConnectedCurves to return the correct list. Could you please guide me?

0 Likes
Message 11 of 16

kandennti
Mentor
Mentor

There is a way to hide only points with the Sketch.arePointsShown property, but I don't think there is a way to hide the SketchEntity.
(The GUI also has no ability to hide.)

0 Likes
Message 12 of 16

nnikbin
Collaborator
Collaborator

@kandennti , so it seem that your code does not solve the problem. Is it correct?

0 Likes
Message 13 of 16

kandennti
Mentor
Mentor

@nnikbin .

 

As far as I can tell, there is no way to hide SketchEntity in Fusion360, and I don't think it is possible in code either.

 

If you can delete it and there is no problem, you can clone it and delete the original, but I feel that the problem may come out later.

# Fusion360API Python script
import adsk.core, adsk.fusion, traceback

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

        # select Control Point Spline
        msg :str = 'Select'
        selFiltter :str = 'SketchCurves'
        sel :adsk.core.Selection = selectEnt(msg ,selFiltter)
        if not sel: return

        crv = sel.entity

        # get geometry
        nurbs = adsk.core.NurbsCurve3D.cast(crv.geometry)
        if not nurbs:
            try:
                nurbs :adsk.core.NurbsCurve3D = crv.geometry.asNurbsCurve
            except:
                pass

        if not nurbs:
            return

        # create clone Nurbs curve
        returnValue, controlPoints, degree, knots, isRational, weights, isPeriodic = nurbs.getData()
        cloneNurbs = adsk.core.NurbsCurve3D.createRational(controlPoints, degree, knots, weights, isPeriodic)

        # add cloneNurbs
        skt :adsk.fusion.Sketch = crv.parentSketch
        skt.sketchCurves.sketchFixedSplines.addByNurbsCurve(cloneNurbs)

        # remove Original Curve
        crv.deleteMe()

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

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

    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        sel = ui.selectEntity(msg, filtterStr)
        return sel
    except:
        return None
Message 14 of 16

nnikbin
Collaborator
Collaborator

Thank you @kandennti ,

 

I think we can simplify your code by using the following code:

 

skt.sketchCurves.sketchFixedSplines.addByNurbsCurve(crv.geometry)

 

Instead of:

 

nurbs = adsk.core.NurbsCurve3D.cast(crv.geometry)
returnValue, controlPoints, degree, knots, isRational, weights, isPeriodic = nurbs.getData()
cloneNurbs = adsk.core.NurbsCurve3D.createRational(controlPoints, degree, knots, weights, isPeriodic)
skt.sketchCurves.sketchFixedSplines.addByNurbsCurve(cloneNurbs)

 

I was surprised to see that even after converting the curve to a fixed spline, findConnectedCurves does not work correctly. For example if you connect a line to the created fixed spline, findConnectedCurves returns just 1 curve. Also double clicking each curve does not select the chain of curves. Of course, I think this behavior is reasonable in some respects.

 

I also tested this behavior with a fixed spline created by intersecting a cone with a plane (actually a conic curve) and the result was the same. It does not chain with other curves.

Message 15 of 16

kandennti
Mentor
Mentor
0 Likes
Message 16 of 16

MichaelT_123
Advisor
Advisor

Hi Fellows,

 

Am I missing something?

Why both:

 

entityTypeName = thisSketchFixedSpline.classType()

entityTypeName = thisSketchFixedSpline.objectType

 

return adsk.fusion.SketchFittedSpline.classType()

 

There are some compilation directives in SketchFixedSpline.h

What effect they have?

 

Regards

MichaelT

MichaelT
0 Likes