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
Message 1 of 26
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]

25 REPLIES 25
Message 2 of 26

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

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

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

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

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)
(rv, ic, ip) = c1.intersections(oc)
app.log(f'{rv=} {ic.count=} {ip.count=}')
for p in ip:

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:

I hope this could help.

Regards,

Jorge Jaramillo

Message 6 of 26

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

Message 7 of 26

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

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

Message 8 of 26

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

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

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

root.xYConstructionPlane
)
skt.name = 'Intersect Points'

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

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

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.

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

Message 11 of 26

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

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,
tolerance: float
):

(rv, points) = ev.getStrokes(minP, maxP, tolerance)
# app.log(f' {minP=} {maxP=} {tolerance=} {len(points)=}')
p1_is_inside: boolean
mat = sk.transform
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:
dist = p2.distanceTo(body.physicalProperties.centerOfMass)
app.log(f'====> {p2.asArray()}  dist to center={dist=}')
else:
if tolerance <= MIN_TOLERANCE:
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}')
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

@Jorge_Jaramillo . Excellent!

@MichaelT_123 's idea is the same as this one, right?

Message 14 of 26

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.

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.

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.

Message 15 of 26

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

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

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

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

``````def getStrokesLike(
fromParameter: float,
toParameter: float,
count: int = 100,

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

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.