Last active
November 9, 2025 21:34
-
-
Save AndreVallestero/72afe2674742fe337eca567997a31373 to your computer and use it in GitHub Desktop.
Fusion 360 convex hull from points script based on https://cad.onshape.com/documents/cc448676dec18cad9d8b2b57/v/8ddc053d4b428dcbe7ac83d5/e/904929219cb958b738066bde
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import adsk.core, adsk.fusion, traceback | |
| handlers = [] | |
| def computeConvexHull(points_input): | |
| try: | |
| points = [(p.x, p.y, p.z) if hasattr(p,'x') else tuple(p) for p in points_input] | |
| n = len(points) | |
| if n < 4: | |
| return [] | |
| def sub(a,b): return (a[0]-b[0],a[1]-b[1],a[2]-b[2]) | |
| def cross(u,v): return (u[1]*v[2]-u[2]*v[1], u[2]*v[0]-u[0]*v[2], u[0]*v[1]-u[1]*v[0]) | |
| def dot(a,b): return a[0]*b[0]+a[1]*b[1]+a[2]*b[2] | |
| EPS = 1e-9 | |
| centroid = (sum(p[0] for p in points)/n, | |
| sum(p[1] for p in points)/n, | |
| sum(p[2] for p in points)/n) | |
| faces = set() | |
| import itertools | |
| for tri in itertools.combinations(range(n),3): | |
| a_idx, b_idx, c_idx = tri | |
| a,b,c = points[a_idx], points[b_idx], points[c_idx] | |
| nrm = cross(sub(b,a), sub(c,a)) | |
| if (nrm[0]**2 + nrm[1]**2 + nrm[2]**2)**0.5 < EPS: | |
| continue | |
| pos_side = neg_side = False | |
| for i in range(n): | |
| if i in tri: continue | |
| d = dot(sub(points[i], a), nrm) | |
| if d > EPS: pos_side = True | |
| if d < -EPS: neg_side = True | |
| if pos_side and neg_side: | |
| continue | |
| to_center = sub(centroid, a) | |
| if dot(nrm, to_center) > 0: | |
| faces.add((a_idx, c_idx, b_idx)) | |
| else: | |
| faces.add((a_idx, b_idx, c_idx)) | |
| except: | |
| app = adsk.core.Application.get() | |
| ui = app.userInterface | |
| ui.messageBox(traceback.format_exc()) | |
| return [(f[0], f[1], f[2]) for f in faces] | |
| class CreatedHandler(adsk.core.CommandCreatedEventHandler): | |
| def notify(self, args): | |
| c = args.command | |
| sel = c.commandInputs.addSelectionInput('pointsSel','Select Points','Pick points for convex hull') | |
| for f in ['SketchPoints','Vertices','ConstructionPoints']: sel.addSelectionFilter(f) | |
| sel.setSelectionLimits(1) | |
| class ExecHandler(adsk.core.CommandEventHandler): | |
| def notify(self, args): | |
| s = c.commandInputs.itemById('pointsSel') | |
| if s.selectionCount<4: | |
| adsk.core.Application.get().userInterface.messageBox("Select at least 4 points."); return | |
| pts=[] | |
| for i in range(s.selectionCount): | |
| ent=s.selection(i).entity | |
| p=None | |
| if isinstance(ent,adsk.fusion.SketchPoint): | |
| p=ent.geometry.copy(); p.transformBy(ent.parentSketch.transform) | |
| elif isinstance(ent,adsk.fusion.BRepVertex): p=ent.geometry | |
| else: adsk.core.Application.get().userInterface.messageBox("Unsupported entity"); return | |
| pts.append((p.x,p.y,p.z)) | |
| fcs=computeConvexHull(pts) | |
| if not fcs: adsk.core.Application.get().userInterface.messageBox("Convex hull failed."); return | |
| coords=[c for p in pts for c in p]; idx=[i for tri in fcs for i in tri] | |
| root = adsk.fusion.Design.cast(adsk.core.Application.get().activeProduct).rootComponent | |
| m=root.meshBodies.addByTriangleMeshData(coords,idx,[],[]); m.name='ConvexHullMesh' | |
| s=root.features.meshConvertFeatures.createInput([m]) | |
| conv=root.features.meshConvertFeatures.add(s) | |
| conv.refinement=2; conv.bodies.item(0).name='ConvexHullSolid' | |
| h = ExecHandler(); c.execute.add(h); handlers.append(h) | |
| def run(context): | |
| try: | |
| app = adsk.core.Application.get() | |
| ui = app.userInterface | |
| design = adsk.fusion.Design.cast(app.activeProduct) | |
| if not design: ui.messageBox('No active design'); return | |
| cmdId='convexHullMeshCmd' | |
| if ui.commandDefinitions.itemById(cmdId): ui.commandDefinitions.itemById(cmdId).deleteMe() | |
| cmd = ui.commandDefinitions.addButtonDefinition(cmdId,'Convex Hull Mesh','Compute hull, create mesh & solid') | |
| h = CreatedHandler(); cmd.commandCreated.add(h); handlers.append(h) | |
| cmd.execute() | |
| adsk.autoTerminate(False) | |
| except: ui.messageBox(traceback.format_exc()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment