Community
Fusion API and Scripts
Got a new add-in to share? Need something specialized to be scripted? Ask questions or share what you’ve discovered with the community.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

the intersection of a sketch curve and a sphere surface

25 REPLIES 25
SOLVED
Reply
Message 1 of 26
S.T0116
1585 Views, 25 Replies

the intersection of a sketch curve and a sphere surface

I wanted to get the intersection of a sketch curve and a sphere surface, but could not find an api to do so.
Using the basic features of fusion360 I was able to get the intersection I wanted to get.

 

The specific steps are as follows.
step1:Create a sketch curve and a sphere (or sphere surface) [sample1.png]

step2:Project a sketch curve on a spherical surface with a 3d sketch by Intersection Curve.
          (sketch > CREATE > Project/Include > Intersection Curve)[sample2.png]

step3:Place a point at the intersection of the sketch curve and the projection curve. [sample3.png]

 

I would like to achieve this procedure with api. Please give me your advice.

25 REPLIES 25
Message 2 of 26
kandennti
in reply to: S.T0116

Hi @S.T0116 .

 

Perhaps there is no direct way to find the intersection of a surface and a curve.

I am trying a little, but this is quite difficult and takes time to find a method.

Message 3 of 26
MichaelT_123
in reply to: S.T0116

Hi Mr. S.T0116

I am using mobile to draft this simple curve/sphere intersecting algorithm ... in the mathematical sense. Mind you ... this is a nonlinear problem, and in the general case, there is no close/analytical solution to it.

If you are familiar a little bit with numerical analysis, do the following:

  1. Parametrize curve; you can use F360 facilities
  2. Take virtual point P(t)
  3. Find its distance to the center of a sphere D(P(T),Sc(r))
  4. Assemble&Solve the nonlinear equation  Eq(D-r=0) using perhaps the standard numerical solver scipy.solve (t, Eq, r, Sc, ...)

Scan the full range of the parameter t, as there might be multiple solutions.

Regards

MichaelT

 

MichaelT
Message 4 of 26
S.T0116
in reply to: S.T0116

@MichaelT_123  @kandennti 
Thank you for the useful information.

The content of the two indicates that critical api does not exist at this time.


As for MichaelT's suggestion, I interpreted it as determining the interior and exterior of the sphere by comparing the distance to the point and the radius, as shown in the figure.

20230508_112242645_iOS.jpg


It may be possible to implement it this way.

I will take MichaelT's reply as a solution this time, but if kandennti  has a better method or code, I would like to know.

Message 5 of 26
Jorge_Jaramillo
in reply to: S.T0116

Hi @S.T0116 ,

 

I was able to solved it with this script:

 

def curves_intersections():
    c1 = root.sketches.item(0).sketchCurves.item(0)
    c2 = root.sketches.item(0).sketchCurves.item(1)
    oc = adsk.core.ObjectCollection.create()
    oc.add(c2)
    (rv, ic, ip) = c1.intersections(oc)
    app.log(f'{rv=} {ic.count=} {ip.count=}')
    for p in ip:
        app.log(f'  {adsk.core.Point3D.cast(p).asArray()}')
        root.sketches.item(0).sketchPoints.add(p)

 

 

I created an sphere, then a sketch on XZ plane, drew a spline line (c1) and the projects the sphere on the plane (c2).

 

The resulting intersection points where create on the same sketch and its coordinates printed in the text command output window.  This is the result:

wtallerdemadera_0-1683553759519.png

 

I hope this could help.

 

Regards,

Jorge Jaramillo

 

 

Message 6 of 26
kandennti
in reply to: S.T0116

@S.T0116 .

 

Are the curves on the sketch plane?
I thought they were 3D curves judging from the image.

Message 7 of 26
S.T0116
in reply to: S.T0116

@Jorge_Jaramillo 
Thank you for the specific script.

Sketch curves are preferred to 3d sketches. For your script, this works for curves in the 2d plane.

My explanation was insufficient.


@kandennti 

You are right.
I think that the idea proposed by MichaelT can be implemented in 3d space.

Message 8 of 26
Jorge_Jaramillo
in reply to: S.T0116

Hi @S.T0116 ,

Sorry, I re-read it and I understood that it was my mistake (too easy to be made in such a way I sent it).

Did you solved it already? I believe I have some idea on how to implement it.

 

Regards,

Jorge Jaramillo

 

 

Message 9 of 26
kandennti
in reply to: S.T0116

@S.T0116 .

 

After much consideration, we created a large number of points on the curve and used the points within a tolerance distance from the center as the intersection points.
However, the accuracy is not good, and in some cases, multiple points that are very close to each other are obtained in areas where there should be only one point of intersection.

# Fusion360API Python script

import traceback
import adsk
import adsk.core as core
import adsk.fusion as fusion

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

        # select face
        msg: str = 'Select SphericalFace'
        selFilter: str = 'SphericalFaces'
        sel: core.Selection = selectEnt(msg, selFilter)
        if not sel:  return
        face: fusion.BRepFace = sel.entity

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

        # find intersect points
        intersectPoints = get_intersect_points(
            face,
            crv
        )
        if len(intersectPoints) < 1: return

        # dump points
        des: fusion.Design = app.activeProduct
        root: fusion.Component = des.rootComponent

        skt: fusion.Sketch = root.sketches.add(
            root.xYConstructionPlane
        )
        skt.name = 'Intersect Points'
        [skt.sketchPoints.add(p) for p in intersectPoints]

        ui.messageBox('Done')

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


def get_intersect_points(
    face: fusion.BRepFace,
    crv: fusion.SketchCurve,
    tolerance: float = 0.00009,
) -> list[core.Point3D]:

    if face.geometry.objectType != core.Sphere.classType():
        return []

    crvGeo: core.Curve3D = crv.worldGeometry
    crvEva: core.CurveEvaluator3D = crvGeo.evaluator

    _, stPrm = crvEva.getParameterAtPoint(
        crv.startSketchPoint.worldGeometry
    )
    _, endPrm = crvEva.getParameterAtLength(
        stPrm,
        crv.length
    )
    _, crvPnts = crvEva.getStrokes(
        stPrm,
        endPrm,
        0.000000001
    )

    sphere: core.Sphere = face.geometry
    origin: core.Point3D = sphere.origin
    radius: float = sphere.radius

    intersectPoints = [p for p in crvPnts 
        if abs(origin.distanceTo(p) - radius) < tolerance]

    return intersectPoints


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

    try:
        app: core.Application = core.Application.get()
        ui: core.UserInterface = app.userInterface
        sel = ui.selectEntity(msg, filterStr)
        return sel
    except:
        return None
Message 10 of 26
kandennti
in reply to: kandennti

I don't think I can express myself well in English when I can't even express myself well in Japanese....

The SurfaceEvaluator object and the CurveEvaluator3D object both have getParameterAtPoint and getPointAtParameter methods.

https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-31dad9b2-ee1d-4216-8100-09ea44f9967a 

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

 

I think it is possible to get some candidate close points using the getStrokes method of the CurveEvaluator3D object.
This method uses two methods to increase the accuracy based on the candidate points.

 

The getParameterAtPoint method always returns a parameter at a close position, even if there is no point on the surface or curve.
If the distance between two points converges to a certain distance, it may be possible to obtain a point with high accuracy, but there may be no guarantee of convergence.


The image is like this. (The green points are the candidate points obtained by the getStrokes method.)

1.png

Message 11 of 26
MichaelT_123
in reply to: kandennti

Hi Kandennti-San,

Your idea is quite tricky ... and might lead to a solution method that doesn't require the cannons of full-blown numerical analysis tools ... just basic ones and a slight modification of your code.

I am still on my mobile, so it would be challenging to write the code ... but I will try to give some hints.

  1. First ... forget about the sphere, breps, surfaces ...
  2. Only the distance between the intersection point and the center of the sphere matters
  3. Now imagine the intersection point and the small tangential segment at it.
  4. If my imagination is correct, one end of the segment will be closer to the center point than the other
  5. You don't need to find tangents directly; I use this concept only for visualization.
  6. For simplicity, I ignore the case here when the curve is tangential to the sphere
  7. Now find the solution through the  iteration
  8. Take two points (P1, P2) on the curve (endpoints in the first iteration)
  9. Check their distances (D1, D2) from the center
  10. If D1 < R and D2 > R, we have at least one intersection point between P1 and P2.
  11. Divide this curve segment 
  12. Check the condition as in step 9 for both subsegments
  13. Continue divisions until the required precision is met.
  14. Implement the above as a recursive function and always check both fork branches (the curve division sub-segments)
  15. Collect intersection points on the way

Regards

MichaelT

 

MichaelT
Message 12 of 26
Jorge_Jaramillo
in reply to: kandennti

Hi All,

 

I get it done with getStrokes() and a recursion function to increase accuracy on each new iteration.

Just lower MIN_TOLERANCE to increase precision and set skt_n (sketch #), cur_n (SketchFittedSpline curve # in the sketch) and body (the sphere).

It will create points in the sketch and display their coordinates and distance to sphere center in text command output window.

 

 

 

def curves_intersections():
    # design: 20230508 esphere - spline intersection

    #--3D--
    INI_TOLERANCE = 0.001
    MIN_TOLERANCE = 1e-20

    def refine_search(minP: float,
                      maxP:float,
                      ev: adsk.core.CurveEvaluator3D,
                      sk: adsk.fusion.Sketch,
                      body: adsk.fusion.BRepBody,
                      tolerance: float
                     ):
        POINT_CONTAINMENT_INSIDE = [adsk.fusion.PointContainment.PointInsidePointContainment, adsk.fusion.PointContainment.PointOnPointContainment]

        (rv, points) = ev.getStrokes(minP, maxP, tolerance)
        # app.log(f' {minP=} {maxP=} {tolerance=} {len(points)=}')
        p1_is_inside: boolean
        mat = sk.transform
        p2: adsk.core.Point3D = points[0].copy()
        p2.transformBy(mat)
        p2_is_inside: boolean = body.pointContainment(p2) in POINT_CONTAINMENT_INSIDE
        for i in range(1, len(points)):
            p1 = p2
            p2 = points[i].copy()
            p2.transformBy(mat)
            p1_is_inside = p2_is_inside
            p2_is_inside = body.pointContainment(p2) in POINT_CONTAINMENT_INSIDE
            if p2_is_inside ^ p1_is_inside:
                #one point inside and the following outside, or the opposite
                if p2_is_inside:
                    if tolerance <= MIN_TOLERANCE:
                        sk.sketchPoints.add(points[i])
                        dist = p2.distanceTo(body.physicalProperties.centerOfMass)
                        app.log(f'====> {p2.asArray()}  dist to center={dist=}')
                else:
                    if tolerance <= MIN_TOLERANCE:
                        sk.sketchPoints.add(points[i-1])
                        dist = p1.distanceTo(body.physicalProperties.centerOfMass)
                        app.log(f'====> {p1.asArray()}  dist to center={dist=}')
                if tolerance > MIN_TOLERANCE:
                    (rv, params) = ev.getParametersAtPoints([points[i-1], points[i]])
                    refine_search(params[0], params[1], ev, sk, body, tolerance/10)


    skt_n = 0 # sketch_number, inside the root component
    cur_n = 0 # curve_number, inside the sketch
    c1 = root.sketches.item(skt_n).sketchCurves.item(cur_n)
    app.log(f'Curve: {c1}')
    body = root.bRepBodies.item(0)
    app.log(f'Body: {body.name}')
    sfs = adsk.fusion.SketchFittedSpline.cast(c1)
    ev = sfs.geometry.evaluator
    refine_search(0.0, 1.0, ev, root.sketches.item(skt_n), body, INI_TOLERANCE)

 

 

 

Hope this help.

 

Best regards,

Jorge Jaramillo

 

Message 13 of 26
kandennti
in reply to: Jorge_Jaramillo

Message 14 of 26
S.T0116
in reply to: S.T0116

Thank you, everyone.

 

I appreciate the sample, but it's taking me some time to understand it because I'm using C++ and have limited knowledge of APIs.

 

@kandennti 

I understand your script. I also tried it and got multiple points at the same crossing point. There are many useful API usage examples, and these could be used to implement @MichaelT_123 's idea. It's one simple and effective solution.

 

@Jorge_Jaramillo 

More time is needed to understand the script. Also, being new to python, I am not sure how to run this function to select curves and spheres. It would be helpful if you could provide the entire script.

I may ask you questions about this script later.

Message 15 of 26
Jorge_Jaramillo
in reply to: kandennti

Yes, it is @MichaelT_123 idea, but except for item #1 since it was the requirement: "(...) I wanted to get the intersection of a sketch curve and a sphere surface (...)", so the sphere and the curve were used.

 

The idea of this algorithm is to find consecutive points over the line where one in inside the sphere and the other is not (or vice-verse), and then refine the search between them the same way until the precision is met.

 

Regards,

Jorge Jaramillo

 

Message 16 of 26
Jorge_Jaramillo
in reply to: S.T0116

Hi @S.T0116 ,

 

Please find attached the python script.  Just create a new python script on fusion360, and replace the main .py file content with this one.

Look for INPUT PARAMETERS section in the script and set them accordingly.  A added some explanations on them.

 

Feel free to ask me any question you might have.

 

Best regards,

Jorge Jaramillo

 

Message 17 of 26

Hi Mr. Jorge Jarammilo,

 

Well done!

... but it could be better 😉.

getStrokes() is an expensive function, as the number of points generated in each iteration increases, so the number of necessary calculations grows in arithmetic or even geometric series.

The good news is that the script can be modified to moderate the processor/memory load.

 

Regards

MichaelT

 

MichaelT
Message 18 of 26

Hi @MichaelT_123 ,

 

What kind of improvement do you suggest?

 

I can tell you that last night when I was testing the algorithm, the first version I wrote was with a single iteration which used a specific tolerance (I believed I tested until 1e-8), it was processing about 2 million points and was taking about 3 minutes to complete.

It was the reason I choose to make it recursive with iterations that allows it to reduce tolerance every time by 1/10th.

With the last version I wrote, it is analyzing 400 points at most for a minimum tolerance of 1e-20, and taking about 1 or 2 seconds to complete.

 

Regards,

Jorge Jaramillo

 

 

Message 19 of 26
kandennti
in reply to: Jorge_Jaramillo

@Jorge_Jaramillo .

 

I thought the getStrokes method could be replaced by a function like this.

def getStrokesLike(
    self: adsk.core.CurveEvaluator3D,
    fromParameter: float,
    toParameter: float,
    count: int = 100,
) -> tuple[bool, list[adsk.core.Point3D]]:

    step = (toParameter - fromParameter) / count
    prms = [fromParameter + step * i for i in range(count)]
    prms.append(toParameter)

    return self.getPointsAtParameters(prms)

However, I am not sure of the appropriate count value, and some oversight has occurred.

 

I think the getStrokes method is fast enough for me.

Message 20 of 26
MichaelT_123
in reply to: kandennti

Hi IntersectingFellow,

 

In each iterations only four points are essential:

  1. Sc
  2. P1
  3. P2
  4. P3 - new division

Thus for each branch of the fork only the last (P3) must be re-computed. Previous P3 take place of P1 or P2 (dependent upon the fork tine)

 

Regards

MichaelT

 

MichaelT

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

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report