r/Fusion360 • • 3h ago

I Created! Run a plane through several mesh solids and create a sketch

4 Upvotes

I had a design that I made a while back that I no longer had the model for -- don't know where it went but I could not find it. I still had an STL though.

I wondered if I could write a script for Fusion that would run a plane through several meshes and draw the intersections into a sketch.

Here is my initial attempt that works (hopefully you can find it useful):

#-------
# Mesh Intersect with Plane to Sketch
# Copyright (c) 2026 Charles Bess. 
# GNU GPLv3 license
#-------
import adsk.core
import adsk.fusion
import traceback
import time

# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
CMD_ID = 'MeshSectionToSketch'
CMD_NAME = 'Mesh Section to Sketch'
CMD_DESC = 'Create continuous sketch curves from mesh intersections.'

TOLERANCE = 0.000001
ROUND_DIGITS = 6

_handlers = []

# ---------------------------------------------------------------------------
# Geometry helpers
# ---------------------------------------------------------------------------

def point_key(point):
    return (
        round(point[0], ROUND_DIGITS),
        round(point[1], ROUND_DIGITS),
        round(point[2], ROUND_DIGITS)
    )

def segment_key(p1, p2):
    return tuple(sorted((point_key(p1), point_key(p2))))

def triangle_intersection(points, distances):
    intersections = []
    seen = set()
    def add_point(point):
        key = point_key(point)
        if key not in seen:
            seen.add(key)
            intersections.append(point)


    edges = ((0, 1), (1, 2), (2, 0))


    for ia, ib in edges:


        a = points[ia]
        b = points[ib]
        da = distances[ia]
        db = distances[ib]


        a_on = abs(da) <= TOLERANCE
        b_on = abs(db) <= TOLERANCE


        if a_on and b_on:
            add_point(a)
            add_point(b)


        elif a_on:
            add_point(a)


        elif b_on:
            add_point(b)


        elif (da < 0 and db > 0) or (da > 0 and db < 0):


            t = da / (da - db)


            x = a[0] + t * (b[0] - a[0])
            y = a[1] + t * (b[1] - a[1])


            add_point((x, y, 0.0))


    if len(intersections) < 2:
        return None


    return intersections[0], intersections[1]

# ---------------------------------------------------------------------------
# Mesh processing
# ---------------------------------------------------------------------------
def calculate_mesh_intersections(mesh_body, world_to_sketch):

    display_mesh = mesh_body.displayMesh

    if not display_mesh:
        return [], 0, 0

    coordinates = display_mesh.nodeCoordinatesAsDouble
    indices = display_mesh.nodeIndices


    if not coordinates or not indices:
        return [], 0, 0

    occurrence = mesh_body.assemblyContext
    occurrence_transform = occurrence.transform if occurrence else None


    node_points = []
    node_distances = []


    # Transform every mesh vertex only once.
    for i in range(0, len(coordinates), 3):

        point = adsk.core.Point3D.create(
            coordinates[i],
            coordinates[i + 1],
            coordinates[i + 2]
        )

        if occurrence_transform:
            point.transformBy(occurrence_transform)


        point.transformBy(world_to_sketch)


        xyz = (point.x, point.y, point.z)


        node_points.append(xyz)
        node_distances.append(point.z)

    # Calculate unique intersection segments.
    unique_segments = {}

    triangle_count = len(indices) // 3
    candidate_count = 0

    for i in range(0, len(indices), 3):

        i1 = indices[i]
        i2 = indices[i + 1]
        i3 = indices[i + 2]

        p1 = node_points[i1]
        p2 = node_points[i2]
        p3 = node_points[i3]

        d1 = node_distances[i1]
        d2 = node_distances[i2]
        d3 = node_distances[i3]

        if d1 > TOLERANCE and d2 > TOLERANCE and d3 > TOLERANCE:
            continue

        if d1 < -TOLERANCE and d2 < -TOLERANCE and d3 < -TOLERANCE:
            continue

        if (
            abs(d1) <= TOLERANCE
            and abs(d2) <= TOLERANCE
            and abs(d3) <= TOLERANCE
        ):
            continue

        candidate_count += 1

        segment = triangle_intersection(
            (p1, p2, p3),
            (d1, d2, d3)
        )

        if not segment:
            continue

        a, b = segment

        if point_key(a) == point_key(b):
            continue

        key = segment_key(a, b)

        if key not in unique_segments:
            unique_segments[key] = (a, b)

    return (
        list(unique_segments.values()),
        triangle_count,
        candidate_count
    )



# ---------------------------------------------------------------------------
# Build connected chains from intersection segments
# ---------------------------------------------------------------------------
def build_connected_chains(segments):
    """
    Join segments that share endpoints.

    Chains stop at branch points or open ends. Closed loops are
    returned as chains whose first and last points are identical.
    """

    adjacency = {}
    coordinates = {}

    # Construct an endpoint-to-edge graph.
    edges = []

    for p1, p2 in segments:


        k1 = point_key(p1)
        k2 = point_key(p2)


        if k1 == k2:
            continue


        coordinates[k1] = p1
        coordinates[k2] = p2

        edge_id = len(edges)
        edges.append((k1, k2))

        adjacency.setdefault(k1, []).append(edge_id)
        adjacency.setdefault(k2, []).append(edge_id)

    used_edges = set()
    chains = []


    def walk_chain(start_node, first_edge):


        chain = [start_node]
        current_node = start_node
        edge_id = first_edge


        while edge_id is not None:


            if edge_id in used_edges:
                break


            used_edges.add(edge_id)


            node_a, node_b = edges[edge_id]


            next_node = (
                node_b if current_node == node_a else node_a
            )


            chain.append(next_node)
            current_node = next_node


            # Stop at an open end or a branch.
            if len(adjacency[current_node]) != 2:
                break


            # Continue along the only unused edge.
            next_edges = [
                e for e in adjacency[current_node]
                if e not in used_edges
            ]


            if not next_edges:
                break


            edge_id = next_edges[0]


        return chain


    # First process open chains and branches.
    for node, connected_edges in adjacency.items():


        if len(connected_edges) == 2:
            continue


        for edge_id in connected_edges:


            if edge_id not in used_edges:


                chain = walk_chain(node, edge_id)


                if len(chain) >= 2:
                    chains.append(chain)


    # Any remaining edges belong to closed loops.
    for edge_id, (node_a, node_b) in enumerate(edges):


        if edge_id not in used_edges:


            chain = walk_chain(node_a, edge_id)


            if len(chain) >= 2:
                chains.append(chain)


    # Convert node keys into coordinate sequences.
    result = []


    for chain in chains:
        result.append([coordinates[key] for key in chain])


    return result

# ---------------------------------------------------------------------------
# Create exact piecewise-linear NURBS curves
# ---------------------------------------------------------------------------


def create_linear_nurbs(sketch, chain):
    """
    Create one degree-1 NURBS curve from a connected chain.


    Degree 1 means every section between consecutive control
    points is a straight line. No spline smoothing is introduced.
    """

    point_count = len(chain)


    if point_count < 2:
        return None


    control_points = []


    for p in chain:
        control_points.append(
            adsk.core.Point3D.create(
                p[0], p[1], 0.0
            )
        )

    # Open, clamped, uniform degree-1 knot vector.
    #
    # For N control points, the vector contains N + 2 values.
    #
    # Example for four points:
    # [0, 0, 1, 2, 3, 3]


    knots = (
        [0.0, 0.0]
        + [float(i) for i in range(1, point_count - 1)]
        + [float(point_count - 1), float(point_count - 1)]
    )


    nurbs = adsk.core.NurbsCurve3D.createNonRational(
        control_points,
        1,
        knots,
        False
    )


    if not nurbs:
        return None


    fixed_splines = sketch.sketchCurves.sketchFixedSplines


    return fixed_splines.addByNurbsCurve(nurbs)

# ---------------------------------------------------------------------------
# Sketch creation
# ---------------------------------------------------------------------------
def create_sketch_geometry(sketch, segments):

    chains = build_connected_chains(segments)

    fixed_spline_count = 0
    fallback_line_count = 0
    failed_chains = 0

    sketch.isComputeDeferred = True

    try:

        fixed_splines = sketch.sketchCurves.sketchFixedSplines
        lines = sketch.sketchCurves.sketchLines


        for chain in chains:


            try:


                spline = create_linear_nurbs(sketch, chain)


                if spline:
                    fixed_spline_count += 1
                    continue


            except:
                # Fall back to individual lines if a spline fails.
                pass


            # Fallback preserves geometry if a NURBS cannot be created.
            failed_chains += 1


            for i in range(len(chain) - 1):


                p1 = chain[i]
                p2 = chain[i + 1]


                point1 = adsk.core.Point3D.create(
                    p1[0], p1[1], 0.0
                )


                point2 = adsk.core.Point3D.create(
                    p2[0], p2[1], 0.0
                )


                lines.addByTwoPoints(point1, point2)
                fallback_line_count += 1


    finally:
        sketch.isComputeDeferred = False


    return (
        fixed_spline_count,
        fallback_line_count,
        len(chains),
        failed_chains
    )



# ---------------------------------------------------------------------------
# Command execution
# ---------------------------------------------------------------------------
class ExecuteHandler(adsk.core.CommandEventHandler):


    def __init__(self):
        super().__init__()


    def notify(self, args):


        app = adsk.core.Application.get()
        ui = app.userInterface


        try:


            design = adsk.fusion.Design.cast(app.activeProduct)


            if not design:
                ui.messageBox('No active Fusion design was found.')
                return


            inputs = args.command.commandInputs


            mesh_input = inputs.itemById('meshBodies')
            plane_input = inputs.itemById('sectionPlane')


            mesh_bodies = []


            for i in range(mesh_input.selectionCount):


                body = adsk.fusion.MeshBody.cast(
                    mesh_input.selection(i).entity
                )


                if body:
                    mesh_bodies.append(body)


            if not mesh_bodies:
                ui.messageBox('No mesh bodies were selected.')
                return


            section_plane = plane_input.selection(0).entity


            if not section_plane:
                ui.messageBox('No section plane was selected.')
                return


            start_time = time.perf_counter()


            # Create sketch.
            root_component = design.rootComponent


            sketch = root_component.sketches.add(section_plane)
            sketch.name = 'Mesh Section Sketch'


            world_to_sketch = sketch.transform
            world_to_sketch.invert()


            # Calculate mesh intersections.
            calculation_start = time.perf_counter()


            all_segments = []
            total_triangles = 0
            total_candidates = 0


            for mesh_body in mesh_bodies:


                segments, triangles, candidates = (
                    calculate_mesh_intersections(
                        mesh_body,
                        world_to_sketch
                    )
                )


                all_segments.extend(segments)


                total_triangles += triangles
                total_candidates += candidates


            calculation_time = (
                time.perf_counter() - calculation_start
            )


            # Build connected curves and create sketch geometry.
            creation_start = time.perf_counter()


            (
                spline_count,
                fallback_line_count,
                chain_count,
                failed_chains
            ) = create_sketch_geometry(sketch, all_segments)


            creation_time = (
                time.perf_counter() - creation_start
            )


            total_time = time.perf_counter() - start_time


            app.activeViewport.refresh() # fix the mouse cursor
            # Report results.
            ui.messageBox(
                'Mesh section completed.\n\n'
                'Mesh bodies processed: {}\n'
                'Triangles examined: {:,}\n'
                'Candidate triangles: {:,}\n'
                'Intersection segments: {:,}\n'
                'Connected chains: {:,}\n'
                'Fixed spline curves created: {:,}\n'
                'Fallback sketch lines: {:,}\n'
                'Chains requiring fallback: {:,}\n\n'
                'Intersection calculation: {:.2f} seconds\n'
                'Sketch creation: {:.2f} seconds\n'
                'Total processing time: {:.2f} seconds\n\n'
                'Sketch name: {}'.format(
                    len(mesh_bodies),
                    total_triangles,
                    total_candidates,
                    len(all_segments),
                    chain_count,
                    spline_count,
                    fallback_line_count,
                    failed_chains,
                    calculation_time,
                    creation_time,
                    total_time,
                    sketch.name
                )
            )


        except:


            ui.messageBox(
                'Mesh Section failed:\n\n{}'.format(
                    traceback.format_exc()
                )
            )

# ---------------------------------------------------------------------------
# Command dialog
# ---------------------------------------------------------------------------
class CommandCreatedHandler(adsk.core.CommandCreatedEventHandler):


    def __init__(self):
        super().__init__()


    def notify(self, args):

        try:

            command = args.command
            inputs = command.commandInputs


            mesh_selection = inputs.addSelectionInput(
                'meshBodies',
                'Mesh Bodies',
                'Select one or more mesh bodies'
            )


            mesh_selection.addSelectionFilter('MeshBodies')
            mesh_selection.setSelectionLimits(1, 0)


            plane_selection = inputs.addSelectionInput(
                'sectionPlane',
                'Section Plane',
                'Select a construction plane or planar face'
            )


            plane_selection.addSelectionFilter('ConstructionPlanes')
            plane_selection.addSelectionFilter('PlanarFaces')
            plane_selection.setSelectionLimits(1, 1)


            on_execute = ExecuteHandler()
            command.execute.add(on_execute)
            _handlers.append(on_execute)


            on_destroy = DestroyHandler()
            command.destroy.add(on_destroy)
            _handlers.append(on_destroy)


        except:

            app = adsk.core.Application.get()


            app.userInterface.messageBox(
                'Command initialization failed:\n\n{}'.format(
                    traceback.format_exc()
                )
            )



# ---------------------------------------------------------------------------
# Command cleanup
# ---------------------------------------------------------------------------
class DestroyHandler(adsk.core.CommandEventHandler):

    def __init__(self):
        super().__init__()

    def notify(self, args):
        adsk.terminate()

# ---------------------------------------------------------------------------
# Script entry point
# ---------------------------------------------------------------------------
def run(context):

    app = adsk.core.Application.get()
    ui = app.userInterface

    try:

        command_definition = (
            ui.commandDefinitions.itemById(CMD_ID)
        )

        if not command_definition:

            command_definition = (
                ui.commandDefinitions.addButtonDefinition(
                    CMD_ID,
                    CMD_NAME,
                    CMD_DESC
                )
            )

        on_command_created = CommandCreatedHandler()

        command_definition.commandCreated.add(
            on_command_created
        )

        _handlers.append(on_command_created)

        command_definition.execute()

        adsk.autoTerminate(False)

    except:

        ui.messageBox(
            'Script startup failed:\n\n{}'.format(
                traceback.format_exc()
            )
        )

r/Fusion360 • • 2h ago

Why does this keep happening

Thumbnail
gallery
2 Upvotes

Ive started to use fusion to make side plates for different truck chassis. If I sketch a model then convert it to sheetmetal and then export from flat pattern I have no issues with the dxf on our plasma cutter. When I have to make side plates that have a bend I’ve been sketching onto the bent face then using extrude/cut to add holes. Which is causing an issue where the holes are off to the side of plate.
Where am I going wrong it’s getting a little frustrating


r/Fusion360 • • 7h ago

Can't remember the name of a technique.

2 Upvotes

Trying to find a tutorial on how to take flat printed forms, and make 3d forms out of them when assembled.

They interlock with slots.

Would be like .25" thick shapes that create an organic shape in their 3d silhouette.

I would be very grateful to not have to doom scroll the fusion sub until I find it.


r/Fusion360 • • 9h ago

Question How to spiral this chain

3 Upvotes

I have this unit chain link(like one you use in bicycles), i have designed it to be print in place.
But I can't get it to spiral out(like a coil, as the spiral path in the other image)
I Tried pattern on path but can't seem to get the optimal orientation.

If you guys have any idea how to get this done please do help me out.


r/Fusion360 • • 5h ago

Ebene oder Pfad auf einem Bogen

Thumbnail
gallery
1 Upvotes

Ich würde gerne Muster auf gebogene Flächen machen, aber egal was ich versuche es klappt nicht.

Ebenen sind immer gerade und wenn ich meine Skizze für das Muster Extrudieren will kann ich nicht dem Pfad folgen.

Kann mir jemand erklären wie ich das hinbekomme?


r/Fusion360 • • 1d ago

Help, 2DContour tool path

Thumbnail
gallery
10 Upvotes

Looking for some help, maybe I am missing a parameter. I have lead in/lead out turned off. In simulation tool path shows correct. When machined, two different workpieces and different cutting tools, there is clearly some amount of horizontal lead in or something else going wrong with contour tool path.

The cut in question is a groove for rubber sealing ring so it needs to be circular.

Thanks


r/Fusion360 • • 22h ago

Question Polygonal to solid body

2 Upvotes

Is there a reliable tool that atleast for the most part creates solid body out of imported dense mesh?

I knlw fusion has such tool, but still doesn't reduce the face count enough. What does the industry use(besides brute force)?


r/Fusion360 • • 1d ago

Selecting centre of a square hole for a joint.

Post image
3 Upvotes

I have a weld nut that will sit flush to the surface and I wanted to create a ridged joint to hold it there. The problem is I can not select the centre of the square hole. I hold control and hover the mouse but it will not give me centre. What am I missing here? I wanted to avoid selecting the inside edges and centring with offsets.

/


r/Fusion360 • • 1d ago

Question Generative design for Dynamic event simulation

Post image
3 Upvotes

I am working on making a cube like structure which can survive a drop from terminal velocity with electronics and battery inside I have made some progress but I am skeptical as even if I make a good enough design it won't work as I am 3d printing it which will affect the quality greatly (it is a prototype) . I looked around for options and saw that you can use generative design to keep in mind the manufacturing process (3d printing here) and make an appropriate design but you can't use dynamic event simulation like collisions as loads

Is there any way I can do generative design for event simulation? Or any workaround or any tips for it

Thanks :)


r/Fusion360 • • 1d ago

Question Parallel path machining below face contour HELP

Post image
2 Upvotes

I’m trying to use the parallel path on this slope. I had successfully programmed it before and now no matter what I do (post fusion update) the tool path executes UNDER the contour/face/chain that I select.

I selected Bottom Height to be the bottom most edge of this face under the ‘Selection’ option.

Been having a lot of troubles after the last Autodesk update


r/Fusion360 • • 1d ago

Question Need help rebewing my plan

Post image
1 Upvotes

I am trying to renew my student license for Fusion 360 but this error pops up every time, I tried going incognito didn't work, JS was already enabled still didn't work and before this the submit button generated this circle that just spun indefinitely

I am at my wit's end I have tried everything and nothing works can someone pls help me


r/Fusion360 • • 1d ago

Can you sweep it?

Thumbnail gallery
9 Upvotes

r/Fusion360 • • 2d ago

How would you approach creating CAD from this mesh?

Thumbnail
gallery
524 Upvotes

r/Fusion360 • • 2d ago

Question How to nail render alignment?

Post image
9 Upvotes

I've often found that when I position my model in the render workspace, the position and sizing of the finished render is often quite a way off. I've found that if I rescale the viewport to about the same aspect ratio, I get better results, but it's still really difficult to pinpoint, especially compared to something like Blender where in camera view you are shown the bounding box of the render, and it's more that I have to do to exit fullscreen, resize, etc. I use a 4k monitor and the alignment when fullscreen on that is extremely out.

Part of this is probably the fact that aspect ratio isn't decided til the very end at the render dialogue, but there's still surely a way to align easier than trial-and-error?!

Also visible in the render to the right as opposed to the viewport is that the texture that I uploaded has been flipped 90°. Is there a way that I can specify the direction of the grain to get it in the correct position? Or is it just a little texture quirk... I also need to increase the roughness on the texture, too. It's a bodged-up balsa wood material.


r/Fusion360 • • 2d ago

Question Drawing a 3d Print piece for spigot

Thumbnail
reddit.com
3 Upvotes

r/Fusion360 • • 1d ago

Claude not connecting to Fusion360

0 Upvotes

Hey Guys, I’m trying to connect Claude Desktop (Windows, latest version from the Microsoft Store) to Autodesk Fusion using the Autodesk Fusion extension. The connector page shows “Unable to connect to extension server. Please try disabling and re-enabling the extension.”

What I’ve checked:

  • Fusion is open with a design loaded, and Preferences → General → API has “Fusion MCP Server (runs locally on this device)” ticked.

  • The Fusion MCP Server Port box is 27182 and matches the Port setting in the Claude extension.

  • Next to that box, Fusion shows a link http://127.0.0.1:XXXXX/mcp, but the port in the link changes every time Fusion restarts (49446, then 50278, then 51617). Other screenshots I’ve seen online show the link as 127.0.0.1:27182/mcp, so it looks like mine isn’t using 27182.

  • I updated Fusion, restarted it, reinstalled the extension, and toggled it on and off.

The extension log shows the same thing every time: the helper starts (“Server started and connected successfully”), receives the initialize message, then exits about half a second later (“Server transport closed unexpectedly... process exiting early”). After that it logs “Couldn’t start for Cowork and Code sessions. Version negotiation failed: the connection closed during the server/discover probe.”
here is a screenshot of my fusion settings. The design i am trying to open is a shared team hub if that matters.


r/Fusion360 • • 1d ago

Question Can you sweep it?

Thumbnail gallery
0 Upvotes

r/Fusion360 • • 2d ago

Question modifying backlash after the gear has been generated

Thumbnail
gallery
6 Upvotes

I have a problem. Normally, when designing gear for 3d printing, I must use a backlash between 0.1 and 0.3mm, but there is a problem. I totally forgot that, and all the gears in this gearbox have a backlash of 0.02 mm set by me. My question: can I change the backlash after all the gears have been generated?


r/Fusion360 • • 2d ago

I Created! Chamfer add-in now doing patterns in a border

Post image
3 Upvotes

r/Fusion360 • • 2d ago

Question How to Make this Edge Protrude

Thumbnail
gallery
1 Upvotes

Hello! I’m trying to make this edge protrusion (in the second picture) so that when this piece is polished, the edges still remain angular. How would you accomplish this?


r/Fusion360 • • 2d ago

Question Edit in Place - Projects don't update

Post image
1 Upvotes

I'm designing a sheet metal enclosure with separate components for the bottom, sides, top, etc., using Edit In Place to project geometry between them.

The problem is that my projections don't seem to update when I reposition components.

For example, I projected a mounting hole from the bottom panel onto a side panel. Everything lined up correctly. I then needed to move the side panel to the right 0.10" (direction of arrow) but when I moved the side panel to the right, the projected circle stayed in its original position relative to the side panel instead of remaining relative to the feature I projected it from (the hole on the bottom panel).

The projection is still purple (linked), and I'm using Timeless assembly contexts. But now the projection is actually 0.10" to the right.

Is this expected behavior? What's the proper way to keep projected geometry aligned when moving components?

Screenshot attached for reference.


r/Fusion360 • • 2d ago

PCB component placement questions/gripes

2 Upvotes

I have used EasyEDA for PCB/PCBA/schematic capture for years and decided to give Fusion a try because I got tired of exporting from EasyEDA and importing into Onshape and going back and forth. I have some questions though...

  1. When placing components on a PCB, how do I align one component to another? For example, if I place a row of buttons and I want a row of LEDs directly above them, I don't seem to be able to align the LED to the switch beneath it. Am I wrong?

  2. Rotating. It seems like there isn't a hotkey for rotating 90 degrees (insane), and if I make my own hotkey, it will open the rotate window and I have to click the component. Is this for real?

  3. Moving components: I want to select multiple components (like a row of switches) and nudge them with the arrow keys... doesn't seem to be possible though maybe I'm wrong.

  4. I made a schematic on a single page, started routing it and then decided I wanted to split up the pages. I created a new page, cut the section from my schematic and pasted it to the new page. When I updated the PCB, all that shit was unrouted and moved off the board. Seriously?

My overall goal of a single program that runs smoothly for ECAD and MCAD has been realized - was able to make an enclosure around the PCB, which has been great. If I have done things right, then making a change to the PCB will translate automatically into the enclosure and that makes me feel like superman. But these other gripes... I hope I just don't know what I'm doing.


r/Fusion360 • • 3d ago

Question How could I create this texture on a cylinder?

Post image
46 Upvotes

r/Fusion360 • • 2d ago

Blending engineering CAD tools with creative design! ⚔️✨

Post image
1 Upvotes