Skip to content

Instantly share code, notes, and snippets.

@stephensmitchell
Last active February 14, 2026 13:52
Show Gist options
  • Select an option

  • Save stephensmitchell/6b6d88bac8dacf6a15b9516bcf02866a to your computer and use it in GitHub Desktop.

Select an option

Save stephensmitchell/6b6d88bac8dacf6a15b9516bcf02866a to your computer and use it in GitHub Desktop.
Alibre Script demos and showcases

Alibre Script demos and showcases

2D Sketch Showcase 1785708902a0807b853cd77debf081ad.md

2DSKETCHPOLYGONTOSPLINETOOL 1885708902a080fdb6dff0567b4bf9c7.md

3D Sketch Showcase 1785708902a080abbf80de769e06e6d0.md

20 Circles 1785708902a080a3b802c178b3f80995.md

20 More Circles 1785708902a080fa8608c428d0ca1e5d.md

AI-Generated Scripts and Add-Ons Database for Alib 1775708902a080fe9ae9dbbb7592b579.md

Alibre Design Import Export Utilities 1e85708902a080c3b3e9ef5e39bc7efd.md

Alibre Script Example 17f5708902a0805dbdd0c06b9c7ab206.md

Aligned Z-axis Helix Generator with Profile Sweep 22c5708902a0808bbcc8df0bc4c345a2.md

Assembly and Part Thumbnail Generator (IronPython 1795708902a080c6999ecdf95c89f54d.md

CAD Sweep Feature Script 22c5708902a0809f8b5bcea9e0c9ab6e.md

Configuration and Parameter Report Script 1e65708902a080c585a7ecf18d2c6f55.md

Configuration Showcase 1a45708902a080f5bc98f328cb9233f3.md

Cycloidal Disk Generator with Performance Metrics 1bf5708902a08096a478f6ef89529a95.md

CycloidalDiskPoints to import into Sketches 1bf5708902a080d5ae50caaa7987465b.md

Cylinder Shared Edge 1a65708902a0806d9f1be1fbad73706b.md

Export all sketches to SVG - Sketch n pattern 1795708902a08057b2bbd1d1ef3b6b51.md

Get Sketch Information 1775708902a080189a1bfc554ddd6a9c.md

Parameter Showcase 1a45708902a080dfa800e20cf5c2901c.md

Part and GPF Loader with Parameter Reader 1875708902a080f389f1e8b33b16284d.md

Plane at Sketch Point 1785708902a08094af2be7e1d827544f.md

python-headaches-with-decimals-and-alibre-lofting- 1d55708902a0807b88a1c86a2ec8419c.md

Python script for generating thumbnails and an Exc 17f5708902a080a98d6ec40b29801b87.md

Random Hole in block 1785708902a080669047cf08127a8933.md

Reference Geometry Showcase 1785708902a080efa20fe2040b358e17.md

SimpleEE (Simple Equation Editor) 2 1945708902a08019a977f66700540524.md

SimpleEE (Simple Equation Editor) 3 2175708902a08047ace2f7c70ec1ddaa.md

SimpleEE (Simple Equation Editor) 1945708902a080529454dcf750f042cb.md

Sweep Stair Beam Sketch 22b5708902a080e79818c376e07f40d4.md

Untitled 1785708902a0807999a4ee7ae4d543cb.md

valid chamfer 1785708902a080f697c4e6fefd43f7d6.md

valid fillet 1785708902a080998eb7e902c43d4973.md

Window Showcase 1785708902a080d5af44ecfb72037b8e.md

20 Circles

ID: A7246742B-4 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 10, 2025 11:17 PM AI summary: The script creates 20 sketches of circles with diameters ranging from 1.0 to 20.0 in Alibre Script, followed by regenerating the model to reflect the added sketches.

Part = CurrentPart()

# Sketch 1
Sketch1 = Part.AddSketch("Sketch1", Part.XYPlane)
Sketch1.StartEditing()
Sketch1.AddCircle(0.0, 0.0, 1.0, False)    # Diameter = 1.0
Sketch1.StopEditing()

# Sketch 2
Sketch2 = Part.AddSketch("Sketch2", Part.XYPlane)
Sketch2.StartEditing()
Sketch2.AddCircle(0.0, 0.0, 2.0, False)    # Diameter = 2.0
Sketch2.StopEditing()

# Sketch 3
Sketch3 = Part.AddSketch("Sketch3", Part.XYPlane)
Sketch3.StartEditing()
Sketch3.AddCircle(0.0, 0.0, 3.0, False)    # Diameter = 3.0
Sketch3.StopEditing()

# Sketch 4
Sketch4 = Part.AddSketch("Sketch4", Part.XYPlane)
Sketch4.StartEditing()
Sketch4.AddCircle(0.0, 0.0, 4.0, False)    # Diameter = 4.0
Sketch4.StopEditing()

# Sketch 5
Sketch5 = Part.AddSketch("Sketch5", Part.XYPlane)
Sketch5.StartEditing()
Sketch5.AddCircle(0.0, 0.0, 5.0, False)    # Diameter = 5.0
Sketch5.StopEditing()

# Sketch 6
Sketch6 = Part.AddSketch("Sketch6", Part.XYPlane)
Sketch6.StartEditing()
Sketch6.AddCircle(0.0, 0.0, 6.0, False)    # Diameter = 6.0
Sketch6.StopEditing()

# Sketch 7
Sketch7 = Part.AddSketch("Sketch7", Part.XYPlane)
Sketch7.StartEditing()
Sketch7.AddCircle(0.0, 0.0, 7.0, False)    # Diameter = 7.0
Sketch7.StopEditing()

# Sketch 8
Sketch8 = Part.AddSketch("Sketch8", Part.XYPlane)
Sketch8.StartEditing()
Sketch8.AddCircle(0.0, 0.0, 8.0, False)    # Diameter = 8.0
Sketch8.StopEditing()

# Sketch 9
Sketch9 = Part.AddSketch("Sketch9", Part.XYPlane)
Sketch9.StartEditing()
Sketch9.AddCircle(0.0, 0.0, 9.0, False)    # Diameter = 9.0
Sketch9.StopEditing()

# Sketch 10
Sketch10 = Part.AddSketch("Sketch10", Part.XYPlane)
Sketch10.StartEditing()
Sketch10.AddCircle(0.0, 0.0, 10.0, False)  # Diameter = 10.0
Sketch10.StopEditing()

# Sketch 11
Sketch11 = Part.AddSketch("Sketch11", Part.XYPlane)
Sketch11.StartEditing()
Sketch11.AddCircle(0.0, 0.0, 11.0, False)  # Diameter = 11.0
Sketch11.StopEditing()

# Sketch 12
Sketch12 = Part.AddSketch("Sketch12", Part.XYPlane)
Sketch12.StartEditing()
Sketch12.AddCircle(0.0, 0.0, 12.0, False)  # Diameter = 12.0
Sketch12.StopEditing()

# Sketch 13
Sketch13 = Part.AddSketch("Sketch13", Part.XYPlane)
Sketch13.StartEditing()
Sketch13.AddCircle(0.0, 0.0, 13.0, False)  # Diameter = 13.0
Sketch13.StopEditing()

# Sketch 14
Sketch14 = Part.AddSketch("Sketch14", Part.XYPlane)
Sketch14.StartEditing()
Sketch14.AddCircle(0.0, 0.0, 14.0, False)  # Diameter = 14.0
Sketch14.StopEditing()

# Sketch 15
Sketch15 = Part.AddSketch("Sketch15", Part.XYPlane)
Sketch15.StartEditing()
Sketch15.AddCircle(0.0, 0.0, 15.0, False)  # Diameter = 15.0
Sketch15.StopEditing()

# Sketch 16
Sketch16 = Part.AddSketch("Sketch16", Part.XYPlane)
Sketch16.StartEditing()
Sketch16.AddCircle(0.0, 0.0, 16.0, False)  # Diameter = 16.0
Sketch16.StopEditing()

# Sketch 17
Sketch17 = Part.AddSketch("Sketch17", Part.XYPlane)
Sketch17.StartEditing()
Sketch17.AddCircle(0.0, 0.0, 17.0, False)  # Diameter = 17.0
Sketch17.StopEditing()

# Sketch 18
Sketch18 = Part.AddSketch("Sketch18", Part.XYPlane)
Sketch18.StartEditing()
Sketch18.AddCircle(0.0, 0.0, 18.0, False)  # Diameter = 18.0
Sketch18.StopEditing()

# Sketch 19
Sketch19 = Part.AddSketch("Sketch19", Part.XYPlane)
Sketch19.StartEditing()
Sketch19.AddCircle(0.0, 0.0, 19.0, False)  # Diameter = 19.0
Sketch19.StopEditing()

# Sketch 20
Sketch20 = Part.AddSketch("Sketch20", Part.XYPlane)
Sketch20.StartEditing()
Sketch20.AddCircle(0.0, 0.0, 20.0, False)  # Diameter = 20.0
Sketch20.StopEditing()

# Regenerate the model to reflect all newly added sketches
Part.Regenerate()

# End of script

20 More Circles

ID: A7246742B-11 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 11, 2025 8:37 AM AI summary: The code creates a 100×100×10 rectangular block and adds 20 sketches on the top face, each containing a circle with a unique diameter ranging from 5 mm to 100 mm, positioned to avoid overlap.

def create_20_circle_sketches():
    """
    Creates a 100×100×10 rectangular block 
    and then adds 20 sketches on the top face.
    Each sketch contains one circle with a unique diameter.
    """
    # 1. Create a new part
    part_obj = Part("MultiCirclePart")

    # 2. Create a base rectangle on the XY-plane (100×100)
    xy_plane = part_obj.GetPlane("XY-Plane")
    base_sketch = part_obj.AddSketch("BaseSketch", xy_plane)
    base_sketch.AddRectangle(0, 0, 100, 100, False)

    # 3. Extrude that rectangle to 10 mm height
    part_obj.AddExtrudeBoss("BaseExtrusion", base_sketch, 10, False)

    # 4. Get the top face (for the new sketches)
    #    This may be "Face<3>", "Face<5>", etc. depending on your system.
    #    If uncertain, list the faces or adjust the name below:
    top_face = part_obj.GetFace("Face<5>")

    # 5. Create 20 sketches in a loop
    #    Each circle has a unique diameter: e.g. 5, 10, 15, ... 100 mm
    #    We also offset each circle horizontally to avoid overlap
    for i in range(1, 21):
        # Example diameter stepping: 5 mm + 5*(i-1)
        circle_diameter = 5 * i  
        # Name each sketch uniquely
        sketch_name = "CircleSketch{}".format(i)
        # Create the sketch on the top face
        circle_sketch = part_obj.AddSketch(sketch_name, top_face)

        # For demonstration, place circles along the X-axis 
        # so they don't overlap (some arbitrary spacing)
        center_x = 5 + (i * 4)   # shift horizontally
        center_y = 50           # keep it mid-plane in Y

        # Add the circle to the newly created sketch
        # The AddCircle call: (centerX, centerY, diameter, IsReference)
        circle_sketch.AddCircle(center_x, center_y, circle_diameter, False)

    print("Successfully created 20 sketches with unique circle diameters.")

# Example usage: 
create_20_circle_sketches()

2D Sketch Showcase

ID: A7246742B-15 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 11, 2025 9:22 AM AI summary: A Python function demonstrates creating a 2D sketch with various shapes including lines, rectangles, circles, arcs, ellipses, polygons, polylines, and B-splines using Alibre Script and IronPython.

def sketch_2d_showcase():
    """
    Demonstrates creating a single 2D sketch with multiple shapes:
    - Lines, rectangle
    - Circle
    - Arc (Center-Start-End)
    - Ellipse
    - Elliptical arc
    - Polygon
    - Polyline
    - Bspline (through points)
    """
    # 1) Create a new Part
    my_part = Part("Sketch2DShowcase")

    # 2) Get the XY-plane to place a sketch
    xy_plane = my_part.GetPlane("XY-Plane")

    # 3) Create one big sketch for demonstration
    sketch = my_part.AddSketch("MultiShapeSketch", xy_plane)

    # -------------------------
    # A. Lines & Rectangle
    # -------------------------
    sketch.AddLine([0,  0], [30,  0], False)
    sketch.AddLine([30, 0], [30, 10], False)
    sketch.AddLine([30,10], [ 0, 10], False)
    sketch.AddLine([ 0,10], [ 0,  0], False)

    sketch.AddRectangle(35, 0, 45, 5, False)

    # -------------------------
    # B. Circle
    # -------------------------
    # centerX=70, centerY=5, diameter=10
    sketch.AddCircle(70, 5, 10, False)

    # -------------------------
    # C. Arc (Center-Start-End)
    # -------------------------
    # center=(95, 5), start=(90, 5), end=(95, 10)
    sketch.AddArcCenterStartEnd(95, 5, 90, 5, 95, 10, False)

    # -------------------------
    # D. Ellipse
    # -------------------------
    # AddEllipse(CenterX, CenterY, MajorDiameter, MinorMajorRatio, MajorAxisAngle, isRef)
    # center=(120,5), major=20, ratio=0.5 => minor=major*0.5, angle=0
    sketch.AddEllipse(120, 5, 20, 0.5, 0.0, False)

    # -------------------------
    # E. Elliptical Arc
    # -------------------------
    # Must pass all 10 arguments:
    #   1) CenterX=150
    #   2) CenterY=5
    #   3) StartX=140
    #   4) StartY=5
    #   5) EndX=150
    #   6) EndY=10
    #   7) MajorAxisDiameter=20
    #   8) MinorMajorRatio=0.5
    #   9) MajorAxisAngle=0.0
    #   10) IsReference=False
    sketch.AddEllipticalArc(150, 5, 140, 5, 150, 10, 20, 0.5, 0.0, False)

    # -------------------------
    # F. Polygon
    # -------------------------
    # AddPolygon(centerX, centerY, diameter, sides, isRef)
    # center=(180,5), diameter=15, 6 sides
    sketch.AddPolygon(180, 5, 15, 6, False)

    # -------------------------
    # G. Polylines
    # -------------------------
    # We'll add a "zigzag" polyline near (0,30)
    poly_points = [  0,30,
                    10,40,
                    20,30,
                    30,40,
                    40,30 ]
    sketch.AddLines(poly_points, False)

    # -------------------------
    # H. Bspline
    # -------------------------
    # Add a spline from (0,50) → (10,60) → (20,55) → (30,65)
    spline_points = [0,50, 10,60, 20,55, 30,65]
    sketch.AddBspline(spline_points, False)

    print("2D Sketch Showcase: Created lines, arcs, circles, ellipse, elliptical arcs, rectangle, polygon, polyline, and a Bspline on one sketch.")

# Uncomment to run:

sketch_2d_showcase()

2DSKETCHPOLYGONTOSPLINETOOL

ID: A7246742B-22 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 27, 2025 5:51 PM AI summary: Tool converts a selected closed sketch into a single B-spline, removing the original sketch and creating a new one with updated subdivision parameters. Users specify steps for lines, arcs, circles, and B-splines before conversion.

# --------------------------------------------------------------
# Script Name: 2DSKETCHPOLYGONTOSPLINETOOL.py
# Purpose:
#   Converts a selected closed sketch into a single Bspline
#   and removes the original sketch. A new sketch is
#   created on the same plane/face, with a new name that
#   includes the subdivision parameters.
#
# Usage:
#   1) Run the script in AlibreScript.
#   2) In the dialog, select the original Sketch to convert.
#   3) Specify the subdivision steps (line/arc/circle/bspline).
#   4) Click "Convert". The old sketch will be removed; a 
#      new sketch with a single Bspline is created with an
#      updated name.
#
# --------------------------------------------------------------

import sys
import math

def SubdivideLine(lineFigure, steps=8):
    """Return a list of [x, y] approximating a line."""
    pts = []
    x1, y1 = lineFigure.StartPoint
    x2, y2 = lineFigure.EndPoint
    for i in range(steps + 1):
        t = float(i)/steps
        x = x1 + t*(x2 - x1)
        y = y1 + t*(y2 - y1)
        pts.append([x, y])
    return pts

def SubdivideArc(arcFigure, steps=16):
    """Return a list of [x, y] approximating a circular arc."""
    pts = []
    cx, cy = arcFigure.Center
    r      = arcFigure.Radius
    arcDeg = arcFigure.Angle    # arc angle in degrees
    # start angle
    sx, sy = arcFigure.StartPoint
    angleStart = math.atan2(sy - cy, sx - cx)
    angleSweep = math.radians(arcDeg)
    for i in range(steps + 1):
        t = float(i)/steps
        ang = angleStart + angleSweep*t
        x = cx + r*math.cos(ang)
        y = cy + r*math.sin(ang)
        pts.append([x, y])
    return pts

def SubdivideCircle(circleFigure, steps=24):
    """Return a list of [x, y] approximating a full circle."""
    pts = []
    cx, cy = circleFigure.Center
    r      = circleFigure.Radius
    for i in range(steps):
        theta = 2.0*math.pi*(float(i)/steps)
        x = cx + r*math.cos(theta)
        y = cy + r*math.sin(theta)
        pts.append([x, y])
    # close the circle explicitly
    pts.append(pts[0])
    return pts

def SubdivideBspline(bsplineFigure, steps=24):
    """Return a list of [x, y] approximating the existing 2D Bspline."""
    subdiv = bsplineFigure.Subdivide(steps)  # [x1,y1, x2,y2, ...]
    pts = []
    for i in range(0, len(subdiv), 2):
        pts.append([subdiv[i], subdiv[i+1]])
    return pts

def GetFigurePoints(fig, lineSteps=8, arcSteps=16, circleSteps=24, bsplineSteps=24):
    """Return [ [x, y], ... ] for a single figure (Line, Arc, Circle, Bspline)."""
    figType = type(fig).__name__
    if figType == 'Line':
        return SubdivideLine(fig, lineSteps)
    elif figType == 'CircularArc':
        return SubdivideArc(fig, arcSteps)
    elif figType == 'Circle':
        return SubdivideCircle(fig, circleSteps)
    elif figType == 'Bspline':
        return SubdivideBspline(fig, bsplineSteps)
    else:
        # ignoring ellipse / ellipticalArc / ellipticalArc3D
        return []

def RemoveDupConsecutive(pts, tol=1e-9):
    """Remove consecutive duplicate points from the list."""
    if not pts:
        return pts
    newList = [pts[0]]
    for i in range(1, len(pts)):
        dx = pts[i][0] - newList[-1][0]
        dy = pts[i][1] - newList[-1][1]
        if (dx*dx + dy*dy) > (tol*tol):
            newList.append(pts[i])
    return newList

def CollectAllSketchPoints(oldSketch, lineSteps=8, arcSteps=16, circleSteps=24, bsplineSteps=24):
    """
    Collect subdivided points from all figures in the oldSketch,
    presumably forming a single closed loop. Return a list of [x,y].
    """
    allPts = []
    figs = oldSketch.Figures
    for f in figs:
        segPts = GetFigurePoints(f, lineSteps, arcSteps, circleSteps, bsplineSteps)
        if not segPts:
            continue
        if not allPts:
            allPts.extend(segPts)
        else:
            # if segPts' first ~ same as last of allPts, skip that
            dx = segPts[0][0] - allPts[-1][0]
            dy = segPts[0][1] - allPts[-1][1]
            if (dx*dx + dy*dy) < 1e-14 and len(segPts) > 1:
                allPts.extend(segPts[1:])
            else:
                allPts.extend(segPts)
    # refine duplicates
    refined = RemoveDupConsecutive(allPts, 1e-9)
    # enforce closure
    if len(refined) > 2:
        dx = refined[0][0] - refined[-1][0]
        dy = refined[0][1] - refined[-1][1]
        if (dx*dx + dy*dy) > 1e-14:
            refined.append(refined[0])
    return refined

def OnConvert(values):
    """
    Callback when user clicks "Convert". 
    We do:
    1) Get selected oldSketch
    2) Grab points
    3) Part.RemoveSketch(oldSketch)
    4) Create newSketch (with appended name) on the same plane/face
    5) Add Bspline
    """
    oldSketch   = values[0]
    lineSub     = values[1]
    arcSub      = values[2]
    circleSub   = values[3]
    bsplineSub  = values[4]

    if not oldSketch:
        print "No sketch selected."
        return

    # gather all points
    coords = CollectAllSketchPoints(oldSketch, lineSub, arcSub, circleSub, bsplineSub)
    if len(coords) < 2:
        print "No valid geometry or not enough points. Aborting."
        return

    oldName = oldSketch.Name
    surf = oldSketch.GetSurface()  # plane or face
    part = oldSketch.GetPart()

    # Remove the old sketch
    part.RemoveSketch(oldSketch)

    # Construct the new name for the sketch by appending the inputs:
    # e.g.  OLDNAME-TO-SPLINE-LINE<lineSub>ARC<arcSub>CIRCLE<circleSub>BSPLINE<bsplineSub>
    newName = "{}-TO-SPLINE-LINE<{}>ARC<{}>CIRCLE<{}>BSPLINE<{}>".format(
        oldName, lineSub, arcSub, circleSub, bsplineSub
    )

    # Create a brand-new sketch with the updated name on the same plane/face
    newSketch = part.AddSketch(newName, surf)

    # Flatten coords into [x1,y1, x2,y2, ...]
    flatten = []
    for p in coords:
        flatten.extend(p)

    # Add the B-spline to the new sketch
    newSketch.AddBspline(flatten, False)

    print "Done. Old sketch removed. New sketch named '%s' was created with a single Bspline." % newName

# Build the dialog for user input
Win = Windows()
dlgInputs = []
dlgInputs.append(['Closed Sketch to Convert', WindowsInputTypes.Sketch, None])
dlgInputs.append(['Line Steps',    WindowsInputTypes.Integer, 8])
dlgInputs.append(['Arc Steps',     WindowsInputTypes.Integer, 16])
dlgInputs.append(['Circle Steps',  WindowsInputTypes.Integer, 24])
dlgInputs.append(['Bspline Steps', WindowsInputTypes.Integer, 24])

Win.UtilityDialog(
    "2DSKETCHPOLYGONTOSPLINETOOL.py",
    "Convert",
    OnConvert,
    None,
    dlgInputs,
    500
)

3D Sketch Showcase

ID: A7246742B-16 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 11, 2025 9:40 AM AI summary: Demonstrates creating a 3D sketch using Alibre Script, including adding lines, an arc, a B-spline, a polyline, and individual points in a single sketch.

def sketch_3d_showcase():
    """
    Demonstrates creating a 3D sketch and adding various 3D figures:
    1) Lines
    2) Arc (center-start-end)
    3) A B-spline (through 3D points)
    4) A polyline (multiple connected segments)
    5) Individual points
    """
    # 1) Create a new Part
    my_part = Part("3DSketchShowcase")

    # 2) Add a 3D sketch to the part
    sketch_3d = my_part.Add3DSketch("My3DSketch")

    # ------------------------------------------------------------------------
    # A) Lines
    # ------------------------------------------------------------------------
    # Add a single line from (0,0,0) to (10,0,5)
    # The signature: .AddLine(X1, Y1, Z1, X2, Y2, Z2) or .AddLine([X1, Y1, Z1], [X2, Y2, Z2])
    sketch_3d.AddLine([0, 0, 0], [10, 0, 5])

    # ------------------------------------------------------------------------
    # B) Arc (Center-Start-End)
    # ------------------------------------------------------------------------
    # AddArcCenterStartEnd(CenterX, CenterY, CenterZ, StartX, StartY, StartZ, EndX, EndY, EndZ)
    # We'll place the arc center at (15,0,0); start at (10,0,5); end at (15,5,5)
    sketch_3d.AddArcCenterStartEnd(15, 0, 0,    # center
                                   10, 0, 5,    # start
                                   15, 5, 5)    # end

    # ------------------------------------------------------------------------
    # C) B-spline
    # ------------------------------------------------------------------------
    # AddBspline(IronPython.Runtime.List) with points [X1, Y1, Z1, X2, Y2, Z2, ...]
    # Let's define a small 3D wave from (0,10,0) -> (5,15,5) -> (10,15,0) -> (15,20,10)
    bspline_points = [
        0, 10, 0,
        5, 15, 5,
        10, 15, 0,
        15, 20, 10
    ]
    sketch_3d.AddBspline(bspline_points)

    # ------------------------------------------------------------------------
    # D) Polyline (multiple connected line segments in 3D)
    # ------------------------------------------------------------------------
    # There's no direct "AddLines" for 3D identical to 2D, but we can do:
    #   .AddLines([x1,y1,z1, x2,y2,z2, x3,y3,z3, ...])
    #   OR use "AddPolyline( AlibreScript.API.Polyline3D )".
    # We'll try .AddLines(...) with a simple zig-zag:
    polyline_points = [
        20,  0, 0,
        25,  5, 5,
        30,  0, 10,
        35,  5, 15
    ]
    sketch_3d.AddLines(polyline_points)

    # ------------------------------------------------------------------------
    # E) Individual points
    # ------------------------------------------------------------------------
    # .AddPoint(X, Y, Z)
    # We'll drop a single reference point at (25,10,5)
    sketch_3d.AddPoint(25, 10, 5)

    print("3D Sketch Showcase completed. Created lines, an arc, a B-spline, a 3D polyline, and a point on a single 3D sketch.")

# Example usage:

sketch_3d_showcase()

Alibre Design Import/Export Utilities

ID: A7246742B-32 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: In progress Category: Testbed Reviewed: No Created time: May 3, 2025 4:03 AM AI summary: Utilities for importing and exporting parts in Alibre Design using Python, including functions for exporting to SAT and STEP formats, and importing from STEP, IGES, and SAT files, with error handling for initialization and file operations.

import clr
clr.AddReference("AlibreScriptAddOn")
clr.AddReference('System.Runtime.InteropServices')
from System.Runtime.InteropServices import Marshal
from AlibreScript.API import *

class AlibreDesignImportExportUtils:
    def __init__(self):
        """Initialize the Alibre Python Utils session."""
        try:
            self.alibre = Marshal.GetActiveObject("AlibreX.AutomationHook")
            self.root = self.alibre.Root
        except Exception as e:
            print "Failed to initialize Alibre Python Utils: %s" % e
            self.alibre = None
            self.root = None

    def export_part_to_sat(self, filename, sat_version=7, save_colors=False):
        """Exports the active part to a SAT file."""
        if not self.alibre or not self.root:
            print "Alibre Python Utils is not initialized."
            return
        try:
            myPart = Part(self.root.TopmostSession)
            myPart.ExportSAT(filename, sat_version, save_colors)
            print "Successfully exported the part to SAT: %s" % filename
        except Exception as e:
            print "An error occurred during SAT export: %s" % e

    def export_part_to_step(self, filename, format="STEP203"):
        """Exports the active part to STEP203 or STEP214."""
        if not self.alibre or not self.root:
            print "Alibre Python Utils is not initialized."
            return
        try:
            myPart = Part(self.root.TopmostSession)
            if format.upper() == "STEP203":
                myPart.ExportSTEP203(filename)
                print "Exported STEP203 to %s" % filename
            elif format.upper() == "STEP214":
                myPart.ExportSTEP214(filename)
                print "Exported STEP214 to %s" % filename
            else:
                print "Unknown STEP format: %s" % format
        except Exception as e:
            print "An error occurred during STEP export: %s" % e

    def import_step_part(self, filepath):
        """Imports a STEP (.step or .stp) file as a part."""
        try:
            part = Part(filepath, Part.FileTypes.STEP)
            print "Successfully imported STEP file: %s" % filepath
            return part
        except Exception as e:
            print "An error occurred during STEP import: %s" % e
            return None

    def import_iges_part(self, filepath):
        """Imports an IGES (.igs/.iges) file as a part."""
        try:
            part = Part(filepath, Part.FileTypes.IGES)
            print "Successfully imported IGES file: %s" % filepath
            return part
        except Exception as e:
            print "An error occurred during IGES import: %s" % e
            return None

    def import_sat_part(self, filepath):
        """Imports a SAT (.sat) file as a part."""
        try:
            part = Part(filepath, Part.FileTypes.SAT)
            print "Successfully imported SAT file: %s" % filepath
            return part
        except Exception as e:
            print "An error occurred during SAT import: %s" % e
            return None

Alibre Script Example

ID: A7246742B-19 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 17, 2025 9:29 PM AI summary: Example Alibre Script demonstrates creating a part, adding sketches, and performing operations like extrusion and cutting using IronPython 2.7 syntax.

# =========================
# Alibre Script Example
# =========================

# Notes:
#  1) This script is “flat”: no class definitions or advanced function definitions.
#  2) Replace any paths or input parameters as needed.
#  3) AlibreScript uses IronPython 2.7 syntax.

# ---------------------------------------------------------
#  Example usage of the AlibreScript API
# ---------------------------------------------------------

# (Optional) Set working units, e.g. millimeters:
Units.Current = UnitTypes.Millimeters

# PART CREATION
# Creates a new part named "Example Part":
MyPart = Part("Example Part")

# Access a default reference plane (e.g. XY-Plane)
XYPlane = MyPart.GetPlane("XY-Plane")

# Add a 2D sketch on the XY-Plane
Sketch1 = MyPart.AddSketch("Sketch1", XYPlane)

# EXAMPLE: Add a rectangle to the sketch
Sketch1.AddRectangle(0, 0, 50, 20, False)

# Extrude Boss
ExtrudeFeature = MyPart.AddExtrudeBoss("Base-Block", Sketch1, 10, False)

# EXAMPLE: Add a circle for a hole, then cut
HoleSketch = MyPart.AddSketch("HoleSketch", MyPart.GetFace("Face<3>"))   # "Face<3>" is just an example face name
# Convert the point (25,10) from the above extrude's face coordinate system
HoleSketch.AddCircle(25, 10, 5, False)
HoleCut = MyPart.AddExtrudeCut("HoleCut", HoleSketch, 10, False)

# End of file

Aligned Z-axis Helix Generator with Profile Sweep [Not Working As Intended]

ID: A7246742B-35 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: July 10, 2025 2:38 AM AI summary: Python script for generating an aligned Z-axis helix with a profile sweep, including parameters for radius, pitch, turns, and step, along with the creation of a helix path and profile plane in a 3D sketch.

See page below for working inplementation

CAD Sweep Feature Script

# Aligned Z-axis helix with profile starting at same point and normal
import math
P = Part("Helix_ZAxisAligned")

# PARAMETERS
radius = 65
pitch = 300
turns = 3
step = 10
profile_radius = 2

# BUILD HELIX AROUND Z-AXIS (centered)
points = []
for a in range(0, 360 * turns + 1, step):
    rad = math.radians(a)
    x = radius * math.cos(rad)
    y = radius * math.sin(rad)
    z = pitch * a / 360.0
    points.extend([x, y, z])

print("Helix path starts at:", [points[0], points[1], points[2]])

# CREATE PATH
Path = P.Add3DSketch("HelixPath")
Path.AddBspline(points)

# CREATE PROFILE PLANE at path start: normal to Z, origin at [0, 0, 0]
Pln = P.AddPlane("ProfilePlane", [0, 0, 1], [0, 0, 0])
Sketch = P.AddSketch("Profile", Pln)

# PROFILE CENTERED AT PATH START (drawn at [radius, 0] on Z-normal plane at origin)
Sketch.AddCircle(radius, 0, profile_radius, False)
print("Profile circle drawn at (%.2f, %.2f) on sketch plane at origin" % (radius, 0))

# SWEEP
P.AddSweepBoss("ZHelixSweep", Sketch, Path, False, Part.EndCondition.EntirePath, None, 0, 0, False)
print("Sweep complete.")

Assembly and Part Thumbnail Generator (IronPython 2.7)

ID: A7246742B-18 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 12, 2025 5:04 AM AI summary: Script generates thumbnails for assembly and part files, saves them as .jpg, and creates an Excel workbook embedding these images in 300×300 pixel cells. User inputs thumbnail size and output folder, and the script handles both parts and assemblies recursively.

# https://www.alibre.com/forum/index.php?threads/add-icon-image-from-the-alibre-file-to-the-parts-list.25649/#post-176092 | @Cator from Alibre Forum

# ------------------------------------------------------------
# Assembly and Part Thumbnail Generator (IronPython 2.7)
# ------------------------------------------------------------
# This script:
#   1. Prompts the user for thumbnail size and output folder.
#   2. Detects whether the current document is an Assembly or Part.
#   3. Explores the assembly/subassemblies to:
#       - Count identical parts (group by normalized name).
#       - Save part/subassembly thumbnails as .jpg.
#   4. Creates an Excel workbook (Images_NET.xlsx) that embeds
#      all images found in the chosen folder, placing each image
#      inside a cell sized 300×300 pixels (approx).
# ------------------------------------------------------------

import clr
import sys
import re
import os
from collections import defaultdict

# Add references for .NET interop with Excel
clr.AddReference("System")
clr.AddReference("Microsoft.Office.Interop.Excel")

from Microsoft.Office.Interop import Excel

# Minimal MsoTriState "enum" to avoid referencing Microsoft.Office.Core
class MsoTriState:
    msoFalse = 0
    msoTrue = -1

# ------------------------------------------------------------
# STEP 1: Prompt user for inputs (thumbnail size + save folder)
# ------------------------------------------------------------

Win = Windows()  # Provided by your CAD/automation environment
Option = [
    ['Thumbnail Size', WindowsInputTypes.Real, 100],
    ['Save Folder',   WindowsInputTypes.Folder, None],
]
Values = Win.OptionsDialog("Image from Assembly", Option, 100)

if Values is None:
    sys.exit()

dimension_thumb = Values[0]
save_path = Values[1]

# ------------------------------------------------------------
# STEP 2: Detect if we have an Assembly or a Part
# ------------------------------------------------------------

def detect_type():
    """
    Detect if the object is an assembly or a part based on common attributes.
    """
    try:
        if hasattr(CurrentAssembly(), 'Parts'):
            obj = CurrentAssembly()
            obj_type = 'Assembly'
        else:
            raise Exception("Invalid assembly")
    except:
        if hasattr(CurrentPart(), 'Name'):
            obj = CurrentPart()
            obj_type = 'Part'
        else:
            raise Exception("Invalid part")
    return obj, obj_type

# ------------------------------------------------------------
# STEP 3: Generate thumbnails for each Part/Subassembly
# ------------------------------------------------------------

def normalize_part_name(part_name):
    """
    Remove unique identifiers like <1>, <2>, etc. from part names.
    """
    return re.sub(r"<\d+>", "", part_name)

def clean_file_name(name):
    """
    Remove invalid characters for Windows file names.
    """
    invalid_chars = r'<>:"/\|?*'
    return re.sub('[{}]'.format(re.escape(invalid_chars)), '_', name)

def ListPartsInAssembly(assembly, save_path):
    """
    Explore the assembly (and subassemblies), group identical parts,
    count quantities, and save thumbnails for parts/subassemblies.
    """
    parts_count = defaultdict(int)

    def process_assembly(asm):
        for part in asm.Parts:
            part_name = part.Name if hasattr(part, 'Name') else str(part)
            normalized_name = normalize_part_name(part_name)
            parts_count[normalized_name] += 1

            cleaned_name = clean_file_name(normalized_name)
            part.SaveThumbnail(
                os.path.join(save_path, cleaned_name + '.jpg'),
                dimension_thumb,
                dimension_thumb
            )

        for sub_asm in asm.SubAssemblies:
            sub_asm_name = sub_asm.Name if hasattr(sub_asm, 'Name') else str(sub_asm)
            cleaned_name = clean_file_name(sub_asm_name)
            sub_asm.SaveThumbnail(
                os.path.join(save_path, cleaned_name + '.jpg'),
                dimension_thumb,
                dimension_thumb
            )
            # Recurse into subassembly
            process_assembly(sub_asm)

    process_assembly(assembly)

    # Print consolidated part list
    print("\nConsolidated Part List:")
    for part, quantity in parts_count.items():
        print("- {}: {}".format(part, quantity))

# ------------------------------------------------------------
# STEP 4: Create Excel workbook and embed images with 300×300 cells
# ------------------------------------------------------------

def GenerateExcelWithImagesNET(image_directory):
    """
    Creates an Excel workbook that lists all images in `image_directory`
    in two columns:
        1. Image Name
        2. Embedded Image (300×300 px, approx)
    """
    # Start Excel
    excel = Excel.ApplicationClass()
    excel.Visible = False  # Change to True if you want to see Excel UI

    # Create a new Workbook (which has one blank worksheet by default)
    workbook = excel.Workbooks.Add()
    sheet = workbook.Worksheets[1]

    # Header cells
    sheet.Cells[1, 1].Value2 = "Image Name"
    sheet.Cells[1, 2].Value2 = "Image"

    # (Optional) freeze the header row or format as needed
    # sheet.Range("A1:B1").Font.Bold = True

    # Convert 300 px to points (approx: 1 px ≈ 0.75 pt at 96 DPI)
    # 300 px * (72 / 96) = 225 pt
    cell_size_points = 225  

    # Set entire column B's width so it can hold ~300 px
    # ~ 42.5 characters in standard Excel measure ≈ 300 px
    sheet.Columns("B").ColumnWidth = 42.5

    row = 2
    valid_extensions = ('.jpg', '.jpeg', '.png', '.bmp', '.gif')

    for filename in os.listdir(image_directory):
        if filename.lower().endswith(valid_extensions):
            image_path = os.path.join(image_directory, filename)

            # Write file name in column A
            sheet.Cells[row, 1].Value2 = filename

            # Set the row height to match 300 px (~225 points)
            sheet.Rows(row).RowHeight = cell_size_points

            # Calculate the cell's top-left in points
            left = sheet.Cells(row, 2).Left
            top = sheet.Cells(row, 2).Top

            # Insert the image as a shape that fits ~300×300 px
            picture = sheet.Shapes.AddPicture(
                Filename=image_path,
                LinkToFile=MsoTriState.msoFalse,      # Do not link to file
                SaveWithDocument=MsoTriState.msoTrue, # Embed in the workbook
                Left=left,
                Top=top,
                Width=cell_size_points,
                Height=cell_size_points
            )

            row += 1

    # Auto-fit Column A for better readability
    sheet.Columns("A").AutoFit()

    # Save workbook in the same folder
    excel_file_path = os.path.join(image_directory, "Images_NET.xlsx")
    workbook.SaveAs(excel_file_path)
    workbook.Close(False)
    excel.Quit()

    print("\nExcel file with images created at: {}".format(excel_file_path))

# ------------------------------------------------------------
# MAIN EXECUTION
# ------------------------------------------------------------

def Main():
    obj, obj_type = detect_type()

    if obj_type == 'Part':
        # Generate a single thumbnail for this part
        print("Current document is a Part; generating thumbnail.")
        cleaned_name = clean_file_name(obj.Name)
        obj.SaveThumbnail(
            os.path.join(save_path, cleaned_name + '.jpg'),
            dimension_thumb,
            dimension_thumb
        )
    else:
        # Treat it as an Assembly
        print("Current document is an Assembly; generating thumbnails.")
        ListPartsInAssembly(obj, save_path)

    # Finally, create the Excel workbook with 300×300 embedded images
    GenerateExcelWithImagesNET(save_path)

Main()

CAD Sweep Feature Script

ID: A7246742B-36 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: July 10, 2025 2:44 AM AI summary: The CAD Sweep Feature Script defines a class for creating sweep features in Alibre Script, including methods for creating planes, adding profile circles, and constructing 3D paths, with an example demonstrating a helical sweep.

image.png

import math

class SweepBuilder:
    def __init__(self, part, name_prefix="SweepFeature"):
        self.part = part
        self.name_prefix = name_prefix
        self.profile_sketch = None
        self.path_sketch = None
        self.plane = None
        self.axis = None
        self.counter = 1

    def create_start_plane_from_path(self, path_points):
        p0 = path_points[0:3]
        p1 = path_points[3:6]
        direction = [p1[i] - p0[i] for i in range(3)]
        self.plane = self.part.AddPlane("%s_StartPlane" % self.name_prefix, direction, p0)
        return self.plane

    def add_profile_circle(self, radius, center_point):
        self.profile_sketch = self.part.AddSketch("%s_Profile" % self.name_prefix, self.plane)
        cx, cy = self.profile_sketch.GlobaltoPoint(center_point[0], center_point[1], center_point[2])
        self.profile_sketch.AddCircle(cx, cy, radius, False)
        return self.profile_sketch

    def add_3d_path(self, path_points):
        self.path_sketch = self.part.Add3DSketch("%s_Path" % self.name_prefix)
        self.path_sketch.AddBspline(path_points)
        return self.path_sketch

    def sweep_profile(self, draft_angle=0.0, outward=False):
        feature_name = "%s_%d" % (self.name_prefix, self.counter)
        self.counter += 1
        return self.part.AddSweepBoss(
            feature_name,
            self.profile_sketch,
            self.path_sketch,
            False,
            Part.EndCondition.EntirePath,
            None,
            0.0,
            draft_angle,
            outward
        )
        
 # SweepExample.py

from math import cos, sin, pi

# Create part
P = Part("HelixSweepTest")
builder = SweepBuilder(P, "HelixSweep")

# Parameters
turns = 3
pitch = 10.0
radius = 5.0
segments = 100
circle_radius = 1.0

# Compute helix points
points = []
for i in range(segments + 1):
    t = (2 * pi * turns) * i / float(segments)
    x = radius * cos(t)
    y = radius * sin(t)
    z = pitch * t / (2 * pi)
    points.extend([x, y, z])

# Construct geometry
plane = builder.create_start_plane_from_path(points)
builder.add_profile_circle(circle_radius, points[0:3])
builder.add_3d_path(points)
builder.sweep_profile(draft_angle=0.0)

Configuration and Parameter Report Script

ID: A7246742B-31 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: April 30, 2025 11:10 PM AI summary: The script generates a configuration and parameter report, displaying local and global configurations and parameters, including their names, types, values, and statuses. It starts by retrieving configuration information and concludes with a report completion message.

001.AD_PKG

from __future__ import print_function

# Always refer to the currently active part
P = CurrentPart()
G = GlobalParameters("001", False)

# Retrieve configuration information
def GetConfigurationInfo(part):
    print("\n[Local Configurations]")
    for config in part.Configurations:
        print("- Name: {}".format(config.Name))
        print("  Active: {}".format("Yes" if config.IsActive else "No"))

# Display all global configurations
def DisplayGlobalConfigurations(gparams):
    print("\n[Global Configurations]")
    for config in gparams.Configurations:
        print("- Name: {}".format(config.Name))
        print("  Active: {}".format("Yes" if config.IsActive else "No"))

# Display all global parameters
def DisplayGlobalParameters(gparams):
    print("\n[Global Parameters]")
    for param in gparams.Parameters:
        print("- Name: {}".format(param.Name))
        print("  Type: {}".format(param.Type))
        print("  Value: {}".format(param.Value))
        print("  Raw Value: {}".format(param.RawValue))
        print("  Equation: {}".format(param.Equation))
        print("  Units: {}".format(param.Units))
        print("  Comment: {}".format(param.Comment))

# Display all local parameters
def DisplayLocalParameters(part):
    print("\n[Local Parameters]")
    for param in part.Parameters:
        print("- Name: {}".format(param.Name))
        print("  Type: {}".format(param.Type))
        print("  Value: {}".format(param.Value))
        print("  Raw Value: {}".format(param.RawValue))
        print("  Equation: {}".format(param.Equation))
        print("  Units: {}".format(param.Units))
        print("  Comment: {}".format(param.Comment))

# Main execution
print("Starting Configuration and Parameter Report...")

GetConfigurationInfo(P)
DisplayLocalParameters(P)
DisplayGlobalParameters(G)
DisplayGlobalConfigurations(G)

print("Report Completed.")

image.png

image.png

>>>
Starting Configuration and Parameter Report...

[Local Configurations]
- Name: PartTest1
  Active: Yes
- Name: PartTest2
  Active: No

[Local Parameters]
- Name: D3
  Type: Distance
  Value: 914.4
  Raw Value: 91.44
  Equation: HEIGHT
  Units: Centimeters
  Comment: 
- Name: D7
  Type: Distance
  Value: 46.6461893250
  Raw Value: 4.66461893250
  Equation: 
  Units: Centimeters
  Comment: 
- Name: D2
  Type: Distance
  Value: 1676.4
  Raw Value: 167.64
  Equation: LENGTH
  Units: Centimeters
  Comment: 
- Name: D4
  Type: Distance
  Value: 88.9419006348
  Raw Value: 8.89419006348
  Equation: 
  Units: Centimeters
  Comment: 
- Name: D6
  Type: Distance
  Value: 1524.0
  Raw Value: 152.4
  Equation: 
  Units: Centimeters
  Comment: 
- Name: D1
  Type: Distance
  Value: 914.4
  Raw Value: 91.44
  Equation: HEIGHT
  Units: Centimeters
  Comment: 

[Global Parameters]
- Name: length
  Type: Distance
  Value: 1676.4
  Raw Value: 167.64
  Equation: 
  Units: Centimeters
  Comment: 
- Name: height
  Type: Distance
  Value: 914.4
  Raw Value: 91.44
  Equation: 
  Units: Centimeters
  Comment: 

[Global Configurations]
- Name: Test1
  Active: No
- Name: Test2
  Active: Yes
Report Completed.
>>>

Configuration Showcase

ID: A7246742B-25 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: February 23, 2025 7:30 PM AI summary: Showcases configuration management using IronPython 2.7, including creating, activating, and modifying configurations, along with locking properties and retrieving configuration information.

# Configurations Showcase

# Ensure compatibility with IronPython 2.7
from __future__ import print_function

# Create a new part
PartName = "ConfigurationDemoPart"
P = Part(PartName)

# Check if a configuration exists
def ConfigurationExists(part, config_name):
    for config in part.Configurations:
        if config.Name == config_name:
            return True
    return False

# Create a new configuration
def CreateConfiguration(part, config_name, base_config=None):
    if not ConfigurationExists(part, config_name):
        if base_config:
            return part.AddConfiguration(config_name, base_config)
        else:
            return part.AddConfiguration(config_name)
    else:
        print("Configuration '{}' already exists.".format(config_name))
        return None

# Retrieve configuration information
def GetConfigurationInfo(part):
    print("\nConfigurations in the part:")
    for config in part.Configurations:
        print("- Name: {}".format(config.Name))
        print("  Active: {}".format("Yes" if config.IsActive else "No"))

# Activate a configuration
def ActivateConfiguration(part, config_name):
    if ConfigurationExists(part, config_name):
        config = part.GetConfiguration(config_name)
        config.Activate()
        print("Activated configuration: {}".format(config_name))
    else:
        print("Configuration '{}' not found.".format(config_name))

# Lock or unlock configuration properties
def ModifyConfigurationLocks(part, config_name, lock=True):
    if ConfigurationExists(part, config_name):
        config = part.GetConfiguration(config_name)
        if lock:
            config.LockAll()
            print("All properties locked for configuration '{}'".format(config_name))
        else:
            config.UnlockAll()
            print("All properties unlocked for configuration '{}'".format(config_name))
    else:
        print("Configuration '{}' not found.".format(config_name))

# Set specific configuration locks
def SetConfigurationLocks(part, config_name, locks):
    if ConfigurationExists(part, config_name):
        config = part.GetConfiguration(config_name)
        config.SetLocks(locks)
        print("Locks set for configuration '{}'".format(config_name))
    else:
        print("Configuration '{}' not found.".format(config_name))

# Get the currently active configuration
def GetActiveConfiguration(part):
    active_config = part.GetActiveConfiguration()
    print("Current active configuration: {}".format(active_config.Name))

# Main execution
print("Starting Configuration Showcase...")

# Create Configurations
CreateConfiguration(P, "Config_A")
CreateConfiguration(P, "Config_B", "Config_A")

# Display all configurations
GetConfigurationInfo(P)

# Activate a configuration
ActivateConfiguration(P, "Config_A")

# Modify configuration locks
ModifyConfigurationLocks(P, "Config_A", lock=True)
ModifyConfigurationLocks(P, "Config_A", lock=False)

# Set specific locks on a configuration
SetConfigurationLocks(P, "Config_A", LockTypes.SuppressNewFeatures | LockTypes.LockColorProperties)

# Get the currently active configuration
GetActiveConfiguration(P)

# Display final configurations
GetConfigurationInfo(P)

print("Configuration Showcase Completed.")

Output:

Starting Configuration Showcase...

Configurations in the part:
- Name: Config<1>
  Active: Yes
- Name: Config_A
  Active: No
- Name: Config_B
  Active: No
Activated configuration: Config_A
All properties locked for configuration 'Config_A'
All properties unlocked for configuration 'Config_A'
Locks set for configuration 'Config_A'
Current active configuration: Config_A

Configurations in the part:
- Name: Config<1>
  Active: No
- Name: Config_A
  Active: Yes
- Name: Config_B
  Active: No
Configuration Showcase Completed.

Cycloidal Disk Generator with Performance Metrics

ID: A7246742B-28 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: March 22, 2025 8:41 PM AI summary: A Cycloidal Disk Generator is implemented using Alibre Script and IronPython, featuring a class to calculate points for the cycloidal disk curve, with performance metrics for point calculation, polyline building, and adding to a sketch.

CycloidalDiskPoints to import into Sketches

from __future__ import division
import math
import sys
print math.pi
from System.Diagnostics import Stopwatch
from System import TimeSpan

class CycloidalDiskCalculator(object):
    def __init__(self, rotor_radius, roller_radius, eccentricity, number_of_rollers):
        # Store parameters
        self.R  = rotor_radius
        self.Rr = roller_radius
        self.E  = eccentricity
        self.N  = number_of_rollers

        # For speed, create local references to math functions
        self._sin   = math.sin
        self._cos   = math.cos
        self._atan2 = math.atan2
        self._pi    = math.pi

    def calc_points(self, num_points):
        """
        Calculates all (x, y) points for the cycloidal disk curve.
        Returns a list of (x, y) tuples. 
        """
        points = []
        # Precompute for speed
        R_div_EN = self.R / (self.E * self.N)
        two_pi = 2 * self._pi

        # Generate parameter t values
        t_values = [i * two_pi / num_points for i in range(num_points)]

        for t in t_values:
            try:
                # Calculate psi
                psi = self._atan2(
                    self._sin((1 - self.N) * t),
                    R_div_EN - self._cos((1 - self.N) * t)
                )
                # Calculate x, y
                x = (self.R * self._cos(t)) - (self.Rr * self._cos(t + psi)) - (self.E * self._cos(self.N * t))
                y = (-self.R * self._sin(t)) + (self.Rr * self._sin(t + psi)) + (self.E * self._sin(self.N * t))
                points.append((x, y))
            except:
                # Ignore any math errors silently (as in the original script)
                pass

        # Close the loop by duplicating the first point
        if points:
            points.append(points[0])

        return points

    def build_polyline(self, points):
        """
        Creates and returns a Polyline object from the provided list of (x, y) points.
        """
        Poly = Polyline()
        for pt in points:
            Poly.AddPoint(PolylinePoint(pt[0], pt[1]))
        return Poly

Win = Windows()
ScriptName = 'Cycloidal Disk Gen'

# Create input window (same as original, minus the image field to match your snippet)
Options = []
Options.append(['Rotor Radius (mm)', WindowsInputTypes.Real, 45])
Options.append(['Roller Radius (mm)', WindowsInputTypes.Real, 6.5])
Options.append(['Eccentricity (mm)', WindowsInputTypes.Real, 1.5])
Options.append(['Number of Rollers', WindowsInputTypes.Integer, 16])
Options.append(['Plane', WindowsInputTypes.Plane, None])

Values = Win.OptionsDialog(ScriptName, Options, 170)
if Values == None:
    sys.exit()

print 'Generating cycloidal disk profile'

# Get user inputs
R  = Values[0]  # Rotor Radius
Rr = Values[1]  # Roller Radius
E  = Values[2]  # Eccentricity
N  = Values[3]  # Number of Rollers
Pl = Values[4]  # Plane Selected

print "Rotor Radius:", R, "Roller Radius:", Rr, "Eccentricity:", E, "Number of Rollers:", N

# Get the current part
Prt = CurrentPart()

# Create the sketch (on XY-plane, or use Pl if you want)
Sk = Prt.AddSketch("Cycloid Disk", Prt.GetPlane('XY-Plane'))

# Number of points for the calculation
num_points = 2000  # Increase resolution
print('Number of Points: ' + str(num_points))

# Create an instance of the new calculation class
calc = CycloidalDiskCalculator(R, Rr, E, N)

watch = Stopwatch.StartNew()

points = calc.calc_points(num_points)

watch.Stop()
ts_calcpoints = watch.Elapsed
print 'Time To Calc Points: {} Hours, {} Minutes, {} Seconds, and {} Milliseconds.'.format(
    ts_calcpoints.Hours,
    ts_calcpoints.Minutes,
    ts_calcpoints.Seconds,
    ts_calcpoints.Milliseconds
)

watch.Restart()

Poly = calc.build_polyline(points)

watch.Stop()
ts_buildpoly = watch.Elapsed
print 'Time To Build Poly: {} Hours, {} Minutes, {} Seconds, and {} Milliseconds.'.format(
    ts_buildpoly.Hours,
    ts_buildpoly.Minutes,
    ts_buildpoly.Seconds,
    ts_buildpoly.Milliseconds
)

watch.Restart()

Sk.AddPolyline(Poly, False)

watch.Stop()
ts_addpolyline = watch.Elapsed
print 'Time To AddPolyline: {} Hours, {} Minutes, {} Seconds, and {} Milliseconds.'.format(
    ts_addpolyline.Hours,
    ts_addpolyline.Minutes,
    ts_addpolyline.Seconds,
    ts_addpolyline.Milliseconds
)
from __future__ import division
import math
import sys
print math.pi
from System.Diagnostics import Stopwatch
from System import TimeSpan

sin_   = math.sin
cos_   = math.cos
atan2_ = math.atan2
pi_    = math.pi

Win = Windows()
ScriptName = 'Cycloidal Disk Gen'

# Create input window
Options = []
Options.append(['Rotor Radius (mm)', WindowsInputTypes.Real, 45])
Options.append(['Roller Radius (mm)', WindowsInputTypes.Real, 6.5])
Options.append(['Eccentricity (mm)', WindowsInputTypes.Real, 1.5])
Options.append(['Number of Rollers', WindowsInputTypes.Integer, 16])
Options.append(['Plane', WindowsInputTypes.Plane, None])

Values = Win.OptionsDialog(ScriptName, Options, 170)
if Values == None:
    sys.exit()

print 'Generating cycloidal disk profile'

# Get user inputs
R  = Values[0]  # Rotor Radius
Rr = Values[1]  # Roller Radius
E  = Values[2]  # Eccentricity
N  = Values[3]  # Number of Rollers
Pl = Values[4]  # Plane Selected

print "Rotor Radius:", R, "Roller Radius:", Rr, "Eccentricity:", E, "Number of Rollers:", N

# Get current part and XY plane
Prt = CurrentPart()
Sk = Prt.AddSketch("Cycloid Disk", Prt.GetPlane('XY-Plane'))

num_points = 1000
print('Number of Points: ' + str(num_points))

two_pi   = 2.0 * pi_
R_div_EN = R / (E * N)

Poly = Polyline()
points = []

watch = Stopwatch.StartNew()

for i in xrange(num_points):
    t = i * two_pi / num_points

    # Calculate psi
    psi = atan2_(sin_((1 - N)*t), (R_div_EN - cos_((1 - N)*t)))

    # Calculate x and y coordinates
    x = (R * cos_(t)) - (Rr * cos_(t + psi)) - (E * cos_(N * t))
    y = (-R * sin_(t)) + (Rr * sin_(t + psi)) + (E * sin_(N * t))

    points.append((x, y))

# Add the first point again to close the polyline
if points:
    points.append(points[0])

watch.Stop()
ts_calcpoints = watch.Elapsed
print 'Time To Calc Points: {} Hours, {} Minutes, {} Seconds, and {} Milliseconds.'.format(
    ts_calcpoints.Hours, ts_calcpoints.Minutes, ts_calcpoints.Seconds, ts_calcpoints.Milliseconds
)

watch.Restart()

# Add points to the polyline
for p in points:
    Poly.AddPoint(PolylinePoint(p[0], p[1]))

watch.Stop()
ts_buildpoly = watch.Elapsed
print 'Time To Build Poly: {} Hours, {} Minutes, {} Seconds, and {} Milliseconds.'.format(
    ts_buildpoly.Hours, ts_buildpoly.Minutes, ts_buildpoly.Seconds, ts_buildpoly.Milliseconds
)

watch.Restart()

# Add the polyline to the sketch
Sk.AddPolyline(Poly, False)

watch.Stop()
ts_addpolyline = watch.Elapsed
print 'Time To AddPolyline: {} Hours, {} Minutes, {} Seconds, and {} Milliseconds.'.format(
    ts_addpolyline.Hours, ts_addpolyline.Minutes, ts_addpolyline.Seconds, ts_addpolyline.Milliseconds
)

Cylinder Shared Edge

ID: A7246742B-27 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: February 25, 2025 9:51 PM AI summary: Python function to find a shared edge between two faces in a 3D model using Alibre Script and IronPython, returning the edge if found or indicating none exists.

def GetSharedEdge(FaceA, FaceB):
    EdgesA = FaceA.GetEdges()
    EdgesB = FaceB.GetEdges()

    for EdgeA in EdgesA:
        for EdgeB in EdgesB:

            VerticesA = EdgeA.GetVertices()
            VerticesB = EdgeB.GetVertices()

            VerticesASet = {(v.X, v.Y, v.Z) for v in VerticesA}
            VerticesBSet = {(v.X, v.Y, v.Z) for v in VerticesB}

            if VerticesASet == VerticesBSet:
                return EdgeA

    return None
P = CurrentPart()

Face1 = P.GetFace("Face<1>")
Face2 = P.GetFace("Face<2>")

SharedEdge = GetSharedEdge(Face1, Face2)

if SharedEdge:
    print("Shared Edge Found:", SharedEdge.Name)
else:
    print("No shared edge between the faces.")

Export all sketches to SVG - Sketch pattern

ID: A7246742B-17 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 12, 2025 12:56 AM AI summary: The script exports all 2D sketches named 'Sketch<1>', 'Sketch<2>', etc., from the current part to SVG files, handling unsaved parts and errors if sketches are not found, with a limit of 50 sketches.

def export_all_sketches_guessing_names():
    """
    Attempts to export every 2D sketch named 'Sketch<1>', 'Sketch<2>', etc.,
    up to some range, from the currently open part. 
    This includes sketches not used by features, 
    but also can produce errors if the name doesn't exist.
    """

    Win = Windows()
    
    # Attempt to get the current part
    try:
        part_obj = CurrentPart()
    except:
        print("Not a part. Canceling.")
        return

    # If part is new/unsaved, prompt user to save
    if not part_obj.FileName:
        folder = Win.SelectFolderDialog("", "Save new part to export sketches?")
        if not folder:
            print("Canceled. No export.")
            return
        part_obj.Save(folder)

    import os
    folder_path = os.path.dirname(part_obj.FileName)

    # Let's define an upper bound. We'll guess up to 50 sketches.
    # Increase if your design might have more.
    max_sketches = 50
    exported_count = 0

    for i in range(1, max_sketches+1):
        sketch_name = "Sketch<{}>".format(i)
        try:
            sketch_obj = part_obj.GetSketch(sketch_name)
            svg_path = os.path.join(folder_path, "Sketch_{}.svg".format(i))
            sketch_obj.ExportSVG(svg_path)
            print("Exported:", sketch_name, "=>", svg_path)
            exported_count += 1
        except:
            # means the sketch name wasn't found or error exporting
            pass
    
    print("Done. Exported {} sketches as .svg in total.".format(exported_count))

# Usage:
# export_all_sketches_guessing_names()

Get Sketch Information

ID: A7246742B-1 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 9, 2025 7:56 PM AI summary: Python script to find and list 3D sketches in a part using a specified naming pattern, handling exceptions for non-existent sketches and printing details about found sketches and their figures.

def find_3d_sketches(part, sketch_format="3DSketch<{}>", max_sketches=50):
    found = []
    for i in range(1, max_sketches+1):
        sketch_name = sketch_format.format(i)
        try:
            sk3d = part.Get3DSketch(sketch_name)
            if sk3d is not None:
                found.append(sk3d)
        except:
            pass
    return found

def main():
    part = CurrentPart()
    if not part:
        print("No active part found. Open a part first.")
        return

    # Change this string if your 3D sketches use a different pattern:
    # e.g. "3D Sketch<{}>", "3D-Sketch<{}>", or "3D Skizze<{}>"
    three_d_sketch_pattern = "3D Sketch<{}>"

    sketches_3d = find_3d_sketches(part, sketch_format=three_d_sketch_pattern, max_sketches=50)
    if not sketches_3d:
        print("No 3D sketches found matching '%s'." % three_d_sketch_pattern)
        return

    for sk in sketches_3d:
        print("----------------------------------------")
        print("  Found 3D Sketch:", sk.Name)
        figures = sk.Figures
        print("  Number of figures:", len(figures))
        for idx, fig in enumerate(figures):
            print("    Figure {}: {}".format(idx+1, type(fig)))

    print("Done!")

main()

Parameter Showcase

ID: A7246742B-26 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: February 23, 2025 8:06 PM AI summary: Showcase of parameter management in Alibre Script, including creation, listing, updating, and deletion of parameters like Width, Height, and EquationParam, with example code demonstrating each operation.

import sys
from AlibreScript.API import *

# Ensure we are using millimeters for script units
Units.Current = UnitTypes.Millimeters

# Create a new part
part = Part("Parameter_Showcase")

# Create parameters (C - Create)
def create_parameters():
    print("Creating parameters...")
    part.AddParameter("Width", ParameterTypes.Distance, 50.0)
    part.AddParameter("Height", ParameterTypes.Distance, ParameterUnits.Centimeters, 5.0)
    part.AddParameter("Angle", ParameterTypes.Angle, 30.0)
    part.AddParameter("HoleDiameter", ParameterTypes.Distance, 12.0)
    part.AddParameter("EquationParam", ParameterTypes.Distance, "Width/2")
    print("Parameters created successfully.")

# Read and list all parameters (R - Read)
def list_parameters():
    print("Listing all parameters...")
    if not part.Parameters:
        print("No parameters found.")
    else:
        for param in part.Parameters:
            print("---------------------------------")
            print("Name: ", param.Name)
            print("Type: ", param.Type)
            print("Units: ", param.Units)
            print("Value: ", param.Value)
            print("Raw Value: ", param.RawValue)
            print("Equation: ", param.Equation)
            print("Comment: ", param.Comment if param.Comment else "None")
    print("---------------------------------")

# Update parameter values and equations (U - Update)
def update_parameters():
    print("Updating parameters...")
    width_param = part.GetParameter("Width")
    if width_param:
        width_param.Value = 75.0
        print("Updated 'Width' parameter to 75.0 mm")
    
    equation_param = part.GetParameter("EquationParam")
    if equation_param:
        equation_param.Equation = "Height * 2"
        print("Updated 'EquationParam' equation to 'Height * 2'")
    
    print("Parameters updated successfully.")

# Delete a parameter (D - Delete)
def delete_parameter(param_name):
    print("Deleting parameter: ", param_name)
    param = part.GetParameter(param_name)
    if param:
        part.RemoveFeature(param.Name)
        print("Parameter deleted: ", param_name)
    else:
        print("Parameter not found: ", param_name)

# Check if a parameter exists
def parameter_exists(param_name):
    return part.GetParameter(param_name) is not None

# Main Execution Flow
create_parameters()
list_parameters()
update_parameters()
list_parameters()
delete_parameter("HoleDiameter")
list_parameters()

print("Parameter showcase completed.")

Output:

Creating parameters...
Parameters created successfully.
Listing all parameters...
---------------------------------
('Name: ', 'Width')
('Type: ', AlibreScript.API.ParameterTypes.Distance)
('Units: ', AlibreScript.API.ParameterUnits.Centimeters)
('Value: ', 50.0)
('Raw Value: ', 5.0)
('Equation: ', '')
('Comment: ', 'None')
---------------------------------
('Name: ', 'EquationParam')
('Type: ', AlibreScript.API.ParameterTypes.Distance)
('Units: ', AlibreScript.API.ParameterUnits.Centimeters)
('Value: ', 25.0)
('Raw Value: ', 2.5)
('Equation: ', 'Width/2')
('Comment: ', 'None')
---------------------------------
('Name: ', 'HoleDiameter')
('Type: ', AlibreScript.API.ParameterTypes.Distance)
('Units: ', AlibreScript.API.ParameterUnits.Centimeters)
('Value: ', 11.999999999999998)
('Raw Value: ', 1.2)
('Equation: ', '')
('Comment: ', 'None')
---------------------------------
('Name: ', 'Height')
('Type: ', AlibreScript.API.ParameterTypes.Distance)
('Units: ', AlibreScript.API.ParameterUnits.Centimeters)
('Value: ', 50.0)
('Raw Value: ', 5.0)
('Equation: ', '')
('Comment: ', 'None')
---------------------------------
('Name: ', 'Angle')
('Type: ', AlibreScript.API.ParameterTypes.Angle)
('Units: ', AlibreScript.API.ParameterUnits.Degrees)
('Value: ', 29.999999999999996)
('Raw Value: ', 29.999999999999996)
('Equation: ', '')
('Comment: ', 'None')
---------------------------------
Updating parameters...
Updated 'Width' parameter to 75.0 mm
Updated 'EquationParam' equation to 'Height * 2'
Parameters updated successfully.
Listing all parameters...
---------------------------------
('Name: ', 'Width')
('Type: ', AlibreScript.API.ParameterTypes.Distance)
('Units: ', AlibreScript.API.ParameterUnits.Centimeters)
('Value: ', 75.0)
('Raw Value: ', 7.5)
('Equation: ', '')
('Comment: ', 'None')
---------------------------------
('Name: ', 'EquationParam')
('Type: ', AlibreScript.API.ParameterTypes.Distance)
('Units: ', AlibreScript.API.ParameterUnits.Centimeters)
('Value: ', 100.0)
('Raw Value: ', 10.0)
('Equation: ', 'Height * 2')
('Comment: ', 'None')
---------------------------------
('Name: ', 'HoleDiameter')
('Type: ', AlibreScript.API.ParameterTypes.Distance)
('Units: ', AlibreScript.API.ParameterUnits.Centimeters)
('Value: ', 11.999999999999998)
('Raw Value: ', 1.2)
('Equation: ', '')
('Comment: ', 'None')
---------------------------------
('Name: ', 'Height')
('Type: ', AlibreScript.API.ParameterTypes.Distance)
('Units: ', AlibreScript.API.ParameterUnits.Centimeters)
('Value: ', 50.0)
('Raw Value: ', 5.0)
('Equation: ', '')
('Comment: ', 'None')
---------------------------------
('Name: ', 'Angle')
('Type: ', AlibreScript.API.ParameterTypes.Angle)
('Units: ', AlibreScript.API.ParameterUnits.Degrees)
('Value: ', 29.999999999999996)
('Raw Value: ', 29.999999999999996)
('Equation: ', '')
('Comment: ', 'None')
---------------------------------
('Deleting parameter: ', 'HoleDiameter')
('Parameter deleted: ', 'HoleDiameter')
Listing all parameters...
---------------------------------
('Name: ', 'Width')
('Type: ', AlibreScript.API.ParameterTypes.Distance)
('Units: ', AlibreScript.API.ParameterUnits.Centimeters)
('Value: ', 75.0)
('Raw Value: ', 7.5)
('Equation: ', '')
('Comment: ', 'None')
---------------------------------
('Name: ', 'EquationParam')
('Type: ', AlibreScript.API.ParameterTypes.Distance)
('Units: ', AlibreScript.API.ParameterUnits.Centimeters)
('Value: ', 100.0)
('Raw Value: ', 10.0)
('Equation: ', 'Height * 2')
('Comment: ', 'None')
---------------------------------
('Name: ', 'HoleDiameter')
('Type: ', AlibreScript.API.ParameterTypes.Distance)
('Units: ', AlibreScript.API.ParameterUnits.Centimeters)
('Value: ', 11.999999999999998)
('Raw Value: ', 1.2)
('Equation: ', '')
('Comment: ', 'None')
---------------------------------
('Name: ', 'Height')
('Type: ', AlibreScript.API.ParameterTypes.Distance)
('Units: ', AlibreScript.API.ParameterUnits.Centimeters)
('Value: ', 50.0)
('Raw Value: ', 5.0)
('Equation: ', '')
('Comment: ', 'None')
---------------------------------
('Name: ', 'Angle')
('Type: ', AlibreScript.API.ParameterTypes.Angle)
('Units: ', AlibreScript.API.ParameterUnits.Degrees)
('Value: ', 29.999999999999996)
('Raw Value: ', 29.999999999999996)
('Equation: ', '')
('Comment: ', 'None')
---------------------------------
Parameter showcase completed.

Part and GPF Loader with Parameter Reader

ID: A7246742B-21 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 26, 2025 1:21 PM AI summary: Python script for loading a part and associated global parameters, creating an output folder with a timestamp, and listing favorite parameters from the GPF, with error handling for missing parts or GPFs.

import math                             # For math operations
from datetime import datetime          # For timestamp
import os, sys                         # For path/file operations & sys.exit
print("Script has started...")

# Step 1: Access the current part
try:
    part = CurrentPart()
    print("Part loaded: {}".format(part.Name))
except Exception as e:
    print("Error: No part is currently loaded in Alibre.\n{}".format(str(e)))
    sys.exit()  # Exit if no part is available

# Step 2: Attempt to access an already-linked GPF
try:
    # Add GPF Link Code Here
    print("GPF loaded (linked to part): {}".format(GPF.Name))
except:
    # If there's no GPF linked, fallback to open a known GPF from disk
    print("No linked GPF found. Trying to open from path...")
    GPFpath = r"{path}"              # Adjust as needed
    GPFname = "New_Global_Parameters_Script"         # The GPF 'internal name'
    try:
        GPF = GlobalParameters(GPFpath, GPFname)
        print("Opened GPF from disk: '{}'".format(GPF.Name))
    except Exception as ex:
        print("Error: Could not open GPF from disk.\n{}".format(str(ex)))
        sys.exit()

# OPTIONAL: You can set units for your script if needed
Units.Current = UnitTypes.Inches

# Step 3: Create the output folder
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")  # For unique naming
output_folder = os.path.join(
    r"{path}",          # Base folder
    "{}_{}_{}".format(part.Name, GPF.Name, timestamp) # E.g. "PartName_GPFName_YYYYMMDD_HHMMSS"
)
os.makedirs(output_folder)
print("Output folder created: {}".format(output_folder))

# Step 4: Read *favorite* parameters from the GPF
Fake_Favorites = [param.Comment for param in GPF.Parameters if param.Comment]
print("Favorite parameters in GPF: {}".format(Fake_Favorites))

# (Optional) Debug or additional listing:
# Show all parameter names, values, and comments
all_names = [p.Name for p in GPF.Parameters]
all_values = [p.Value for p in GPF.Parameters]
all_comments = [p.Comment for p in GPF.Parameters]

print("All Param Names: ", all_names)
print("All Param Values:", all_values)
print("All Param Comments (Fake_Favorites):", all_comments)
print("Script completed successfully.")

Plane at Sketch Point

ID: A7246742B-12 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 11, 2025 8:49 AM AI summary: Creates a 50×50×10 block, adds a sketch with a point at (25, 25), converts it to 3D coordinates, and creates a reference plane at that location using a specified normal vector.

def create_plane_at_sketch_point():
    """
    1. Creates a part with a 50×50×10 block.
    2. Adds a sketch on the top face and places a point at (25, 25).
    3. Converts that point's 2D location into 3D global coordinates.
    4. Creates a reference plane at that 3D location, 
       using a chosen normal vector (e.g. [0,0,1]) for orientation.
    """
    # 1) Create the part
    part_obj = Part("PlaneAtPointPart")

    # 2) Create a base rectangle on the XY-plane (50×50)
    xy_plane = part_obj.GetPlane("XY-Plane")
    base_sketch = part_obj.AddSketch("BaseSketch", xy_plane)
    base_sketch.AddRectangle(0, 0, 50, 50, False)

    # 3) Extrude 10 mm
    part_obj.AddExtrudeBoss("BaseExtrusion", base_sketch, 10, False)

    # 4) Identify the top face created by the extrusion 
    #    (commonly "Face<5>" or similar).
    top_face = part_obj.GetFace("Face<5>")

    # 5) Add a sketch on that top face
    point_sketch = part_obj.AddSketch("PointSketch", top_face)

    # 6) Place a point at (25, 25) in the local 2D coordinates 
    #    of the new sketch (center region).
    #    This is not a reference point, so isReference=False.
    point_sketch.AddPoint(25, 25, False)

    # 7) Convert the 2D point location to 3D global coordinates
    #    The newly added point is figure[0], but safer to reference last figure index:
    sketch_pt_2d = point_sketch.Figures[-1]  # The newly added AlibreScript figure
    x2d, y2d = sketch_pt_2d.X, sketch_pt_2d.Y  # 2D coords in the sketch
    pt_3d = point_sketch.PointtoGlobal(x2d, y2d)
    # pt_3d is now a Python list [globalX, globalY, globalZ]

    # 8) Create a plane at the 3D point location 
    #    Let the plane be parallel to XY-plane → normal vector is [0, 0, 1].
    #    Or pick any normal of your choice: e.g., [1, 1, 1].
    normal_vector = [0, 0, 1]
    plane_name = "PlaneAtPoint"
    # Use AddPlane( name, normal_vector, point_in_3d )
    #   Normal vector can be non-normalized. 
    #   The point_in_3d is [X, Y, Z] in part coordinates.
    new_plane = part_obj.AddPlane(plane_name, normal_vector, pt_3d)

    print("Created a block and added a plane at the location of a sketch point.")
    print("Plane name:", plane_name)
    print("Plane location:", pt_3d)
    print("Plane normal vector:", normal_vector)

# Uncomment to run directly:
create_plane_at_sketch_point()

Python script for generating thumbnails and an Excel report

ID: A7246742B-20 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 18, 2025 1:58 AM AI summary: Python script generates thumbnails and an Excel report for parts and assemblies, including utility functions for file naming, thumbnail saving, and Excel integration with images and quantities.

import clr
import sys
import re
import os

from collections import defaultdict

clr.AddReference("System")
clr.AddReference("Microsoft.Office.Interop.Excel")

from Microsoft.Office.Interop import Excel

################################################################
# Minimal MsoTriState "enum" for AddPicture in .NET Excel interop
################################################################
class MsoTriState:
    msoFalse = 0
    msoTrue = -1

###########################################################
# 1) UTILITY FUNCTIONS
###########################################################

def clean_file_name(name):
    """
    Replace any invalid Windows file-system characters with underscores.
    """
    if not isinstance(name, basestring):
        # Fallback if name is None or some other non-string
        return "NoName"

    invalid_chars = r'<>:"/\\|?*'
    return re.sub('[{}]'.format(re.escape(invalid_chars)), '_', name)

def normalize_part_name(part_name):
    """
    Remove angle-bracket instance tags like <1>, <2>, etc.
    """
    return re.sub(r"<\d+>", "", part_name)

def debug_print(*args):
    """
    Simple helper so we can add debugging lines. 
    Example usage: debug_print("Message:", value)
    """
    msg = " ".join(str(a) for a in args)
    print(msg)

###########################################################
# 2) PROMPT FOR THUMBNAIL SIZE & SAVE FOLDER
###########################################################

Win = Windows()  # Provided by Alibre Script environment
Option = [
    ['Thumbnail Size',  WindowsInputTypes.Real,   100],
    ['Save Folder',     WindowsInputTypes.Folder, None],
]
Values = Win.OptionsDialog("Image from Assembly", Option, 100)
if Values is None:
    sys.exit()  # user canceled

dimension_thumb = Values[0]  # e.g. 100
save_path      = Values[1]  # user-chosen folder

if not os.path.isdir(save_path):
    raise EnvironmentError("The selected folder does not exist: " + save_path)

debug_print("### DEBUG PRINT ###  Using dimension:", dimension_thumb)
debug_print("### DEBUG PRINT ###  Thumbnails and Excel will be in:", save_path)

###########################################################
# 3) DETECT ASSEMBLY OR PART
###########################################################
def detect_type():
    """
    Returns a tuple: (obj, typeString) 
    where typeString is 'Assembly' or 'Part'.
    """
    try:
        if hasattr(CurrentAssembly(), 'Parts'):
            return (CurrentAssembly(), 'Assembly')
        else:
            raise Exception("Not a valid assembly")
    except:
        if hasattr(CurrentPart(), 'Name'):
            return (CurrentPart(), 'Part')
        else:
            raise Exception("Document is neither valid Part nor Assembly")

###########################################################
# 4) ENUMERATE PARTS IN AN ASSEMBLY & COUNT QUANTITIES
###########################################################
Assembly_Name = None
Assembly_DNum = None

def count_parts_in_assembly(assembly):
    """
    Returns a dict { normalizedName : quantity }.
    Also sets global Assembly_Name and Assembly_DNum from the top-level.
    """
    parts_count = defaultdict(int)

    def process_asm(asm):
        global Assembly_Name
        global Assembly_DNum

        Assembly_Name = asm.Name or "Assembly"
        Assembly_DNum = asm.DocumentNumber or "NoDocNum"

        # Count top-level parts
        for p in asm.Parts:
            pname = normalize_part_name(p.Name)
            parts_count[pname] += 1

        # Sub-assemblies
        for sa in asm.SubAssemblies:
            sname = normalize_part_name(sa.Name)
            parts_count[sname] += 1
            process_asm(sa)  # recursion

    process_asm(assembly)
    return parts_count

###########################################################
# 5) THUMBNAIL GENERATION
###########################################################
def generate_thumbnails_with_quantities(assembly, parts_count, folderpath):
    """
    Saves a single thumbnail for each unique part/sub-assembly:
        {CleanedPartName};{CleanedDocNumber};{Quantity}.jpg
    """
    saved_thumbnails = set()

    def save_thumb(name, docnum, quantity, item_obj):
        """
        Actually do the SaveThumbnail to folderpath, with debug prints.
        """
        n_safe = name or "NoName"
        d_safe = docnum or "NoDocNum"

        c_name   = clean_file_name(n_safe)
        c_docnum = clean_file_name(d_safe)

        final_filename = "{};{};{}.jpg".format(c_name, c_docnum, quantity)
        path_out = os.path.join(folderpath, final_filename)

        geometry_hash = getattr(item_obj, 'GeometryHash', id(item_obj))
        unique_id = (final_filename, geometry_hash)

        if unique_id not in saved_thumbnails:
            debug_print("### DEBUG PRINT ###  Saving thumbnail:", path_out)
            item_obj.SaveThumbnail(path_out, dimension_thumb, dimension_thumb)
            saved_thumbnails.add(unique_id)
        else:
            debug_print("### DEBUG PRINT ###  Skipped duplicate thumbnail:", final_filename)

    def traverse_asm(asm):
        # parts
        for p in asm.Parts:
            p_name = normalize_part_name(p.Name)
            p_doc  = p.DocumentNumber
            p_qty  = parts_count[p_name]
            save_thumb(p_name, p_doc, p_qty, p)

        # sub-assemblies
        for sa in asm.SubAssemblies:
            sa_name = normalize_part_name(sa.Name)
            sa_doc  = sa.DocumentNumber
            sa_qty  = parts_count[sa_name]
            save_thumb(sa_name, sa_doc, sa_qty, sa)

            traverse_asm(sa)

    traverse_asm(assembly)

###########################################################
# 6) BUILD THE EXCEL WORKSHEET WITH IMAGES
###########################################################
def GenerateExcelWithImagesNET(image_directory):
    """
    1) Loops over all .jpg/.png/etc. in 'image_directory'.
    2) Splits filename on semicolons: "PartName;DocNum;Qty.jpg".
    3) Writes name, docnum, qty in columns A,B,D.
    4) Embeds the image in column C.
    5) Saves Excel as: "<Assembly_DNum> <Assembly_Name>.xlsx".
    """
    debug_print("### DEBUG PRINT ###  Scanning directory for thumbnails:", image_directory)

    excel = Excel.ApplicationClass()
    excel.Visible = False

    workbook = excel.Workbooks.Add()
    sheet = workbook.Worksheets[1]

    # HEADERS
    sheet.Cells[1, 1].Value2 = "Part Name"
    sheet.Cells[1, 2].Value2 = "Doc #"
    sheet.Cells[1, 3].Value2 = "Image"
    sheet.Cells[1, 4].Value2 = "Quantity"
    sheet.Cells[1, 5].Value2 = "Purchased"
    sheet.Cells[1, 6].Value2 = "Ready"

    sheet.Columns("C").ColumnWidth = 15

    row = 2
    valid_extensions = ('.jpg', '.jpeg', '.png', '.bmp', '.gif')

    # We'll make images about 75 points high/wide
    cell_size_points = 75

    all_files = os.listdir(image_directory)
    if not all_files:
        debug_print("### DEBUG PRINT ###  WARNING: No files found in folder:", image_directory)

    for filename in all_files:
        fn_lower = filename.lower()
        if fn_lower.endswith(valid_extensions):
            debug_print("### DEBUG PRINT ###  Found image file:", filename)

            base_no_ext, ext = os.path.splitext(filename)
            parts = base_no_ext.split(';')
            if len(parts) < 3:
                debug_print("### DEBUG PRINT ###  Skipping file (not enough semicolons):", filename)
                continue

            parted_name   = parts[0]
            parted_docnum = parts[1]
            parted_qty_str = parts[2]

            try:
                parted_qty = int(parted_qty_str)
            except:
                parted_qty = 1

            # Write data in columns A,B,D
            sheet.Cells[row, 1].Value2 = parted_name
            sheet.Cells[row, 2].Value2 = parted_docnum
            sheet.Cells[row, 4].Value2 = parted_qty

            # Row height for image
            sheet.Rows[row].RowHeight = cell_size_points

            image_path = os.path.join(image_directory, filename)
            left = sheet.Cells[row, 3].Left
            top  = sheet.Cells[row, 3].Top

            # Insert the picture
            picture = sheet.Shapes.AddPicture(
                Filename=image_path,
                LinkToFile=MsoTriState.msoFalse,
                SaveWithDocument=MsoTriState.msoTrue,
                Left=left,
                Top=top,
                Width=cell_size_points,
                Height=cell_size_points
            )

            row += 1

    sheet.Columns("A").AutoFit()
    sheet.Columns("B").AutoFit()

    global Assembly_DNum
    global Assembly_Name

    # If we never set them => single Part fallback
    if not Assembly_DNum:
        Assembly_DNum = "PART"
    if not Assembly_Name:
        Assembly_Name = "SINGLE"

    # Clean them for final path:
    Assembly_DNum  = clean_file_name(Assembly_DNum)
    Assembly_Name  = clean_file_name(Assembly_Name)

    excel_file_path = os.path.join(image_directory,
        "{} {}.xlsx".format(Assembly_DNum, Assembly_Name)
    )

    debug_print("### DEBUG PRINT ###  Saving Excel to:", excel_file_path)

    workbook.SaveAs(excel_file_path)
    workbook.Close(False)
    excel.Quit()

    debug_print("### DEBUG PRINT ###  Excel file with images created at:", excel_file_path)

###########################################################
# 7) MAIN
###########################################################
def Main():
    try:
        doc_obj, doc_type = detect_type()
    except Exception as exc:
        print("Error detecting Part or Assembly:", exc)
        return

    debug_print("### DEBUG PRINT ###  Detected type:", doc_type)

    if doc_type == 'Part':
        debug_print("### DEBUG PRINT ###  Single Part scenario.")
        part = doc_obj
        c_name  = clean_file_name(part.Name or "Part")
        c_docno = clean_file_name(part.DocumentNumber or "NoDocNum")
        final_filename = "{};{};1.jpg".format(c_name, c_docno)
        path_out = os.path.join(save_path, final_filename)

        debug_print("### DEBUG PRINT ###  Saving Part thumbnail:", path_out)
        part.SaveThumbnail(path_out, dimension_thumb, dimension_thumb)

    else:
        debug_print("### DEBUG PRINT ###  Assembly scenario: Counting parts.")
        parts_count = count_parts_in_assembly(doc_obj)

        debug_print("### DEBUG PRINT ###  Generating thumbnails with doc # + quantity.")
        generate_thumbnails_with_quantities(doc_obj, parts_count, save_path)

    debug_print("### DEBUG PRINT ###  Building Excel sheet from generated images.")
    GenerateExcelWithImagesNET(save_path)

Main()

python-headaches-with-decimals-and-alibre-lofting-error

ID: A7246742B-30 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: Done Category: Research Reviewed: No Created time: April 14, 2025 6:58 PM AI summary: Python script for processing 3D point data from a TXT file, creating multiple splines, and generating reference points and planes in Alibre using IronPython. Includes functions for reading input, defining point ranges, and adding sketches to the current part.

import fpformat
Win = Windows()
CurrentPart = CurrentPart()

txtfile = Win.OpenFileDialog('Select 3D Pojnts in TXT,mm',
                             'TXT files(*.*)|*.txt*',
                             '.txt')
f = open(txtfile, 'r')
datareader2 = f.read()
f.close()

data_into_list = datareader2.replace('\n', ',').split(",")
Points_Full = data_into_list

print 'Input Number of Guide Curves (typ - 10), then press ENTER'
NumberOfSections = int(Read())

length = (len(Points_Full) // (NumberOfSections * 3))
print(length)

# Break with While Loop
# Point Ranges
Points_1_range  = range(0,           (length*3))
Points_2_range  = range(length*3,    (3*2*length))
Points_3_range  = range(3*2*length, (3*3*length))
Points_4_range  = range(3*3*length, (3*4*length))
Points_5_range  = range(3*4*length, (3*5*length))
Points_6_range  = range(3*5*length, (3*6*length))
Points_7_range  = range(3*6*length, (3*7*length))
Points_8_range  = range(3*7*length, (3*8*length))
Points_9_range  = range(3*8*length, (3*9*length))
Points_10_range = range(3*9*length, (3*10*length))

# Convert to floats directly
Points_1  = [float(Points_Full[w])   for w in Points_1_range]
Points_2  = [float(Points_Full[ww])  for ww in Points_2_range]
Points_3  = [float(Points_Full[www]) for www in Points_3_range]
Points_4  = [float(Points_Full[xxxx]) for xxxx in Points_4_range]
Points_5  = [float(Points_Full[xxxxx]) for xxxxx in Points_5_range]
Points_6  = [float(Points_Full[xxxxxx]) for xxxxxx in Points_6_range]
Points_7  = [float(Points_Full[xxxxxxx]) for xxxxxxx in Points_7_range]
Points_8  = [float(Points_Full[xxxxxxxx]) for xxxxxxxx in Points_8_range]
Points_9  = [float(Points_Full[xxxxxxxxx]) for xxxxxxxxx in Points_9_range]
Points_10 = [float(Points_Full[xxxxxxxxxx]) for xxxxxxxxxx in Points_10_range]

cycle = range(length)

###############################################################################
# Helper function: "fix to 4 decimals, then back to float"
# If you don't need the decimal trimming, you can skip fpformat.fix(...) entirely.
###############################################################################
def to_float4(value):
    # Convert 'value' to a string with 4 decimals, then back to float
    return float(fpformat.fix(value, 4))

###############################################################################
# 1st Spline
###############################################################################
Path1 = CurrentPart.Add3DSketch('Spline1')
Points1 = []
for i in cycle:
    ix = i*3
    X11 = to_float4(Points_1[ix])
    Y11 = to_float4(Points_1[ix+1])
    Z11 = to_float4(Points_1[ix+2])
    Points1.extend([X11, Y11, Z11])

Path1.AddBspline(Points1)

# sample points for planes or references
SP1  = [Points1[0],   Points1[1],   Points1[2]]
SP11 = [Points1[150], Points1[151], Points1[152]]
SP21 = [Points1[300], Points1[301], Points1[302]]

CurrentPart.AddPoint('SP1',  SP1[0],  SP1[1],  SP1[2])
CurrentPart.AddPoint('SP11', SP11[0], SP11[1], SP11[2])
CurrentPart.AddPoint('SP21', SP21[0], SP21[1], SP21[2])

###############################################################################
# 2nd Spline
###############################################################################
Path2 = CurrentPart.Add3DSketch('Spline2')
Points2 = []
for i in cycle:
    ix = i*3
    X12 = to_float4(Points_2[ix])
    Y12 = to_float4(Points_2[ix+1])
    Z12 = to_float4(Points_2[ix+2])
    Points2.extend([X12, Y12, Z12])

Path2.AddBspline(Points2)

SP2  = [Points2[0],   Points2[1],   Points2[2]]
SP12 = [Points2[150], Points2[151], Points2[152]]
SP22 = [Points2[300], Points2[301], Points2[302]]

CurrentPart.AddPoint('SP2',  SP2[0],  SP2[1],  SP2[2])
CurrentPart.AddPoint('SP12', SP12[0], SP12[1], SP12[2])
CurrentPart.AddPoint('SP22', SP22[0], SP22[1], SP22[2])

###############################################################################
# 3rd Spline
###############################################################################
Path3 = CurrentPart.Add3DSketch('Spline3')
Points3 = []
for i in cycle:
    ix = i*3
    X13 = to_float4(Points_3[ix])
    Y13 = to_float4(Points_3[ix+1])
    Z13 = to_float4(Points_3[ix+2])
    Points3.extend([X13, Y13, Z13])

Path3.AddBspline(Points3)

SP3  = [Points3[0],   Points3[1],   Points3[2]]
SP13 = [Points3[150], Points3[151], Points3[152]]
SP23 = [Points3[300], Points3[301], Points3[302]]

CurrentPart.AddPoint('SP3',  SP3[0],  SP3[1],  SP3[2])
CurrentPart.AddPoint('SP13', SP13[0], SP13[1], SP13[2])
CurrentPart.AddPoint('SP23', SP23[0], SP23[1], SP23[2])

###############################################################################
# 4th Spline
###############################################################################
Path4 = CurrentPart.Add3DSketch('Spline4')
Points4 = []
for i in cycle:
    ix = i*3
    X14 = to_float4(Points_4[ix])
    Y14 = to_float4(Points_4[ix+1])
    Z14 = to_float4(Points_4[ix+2])
    Points4.extend([X14, Y14, Z14])

Path4.AddBspline(Points4)

SP4  = [Points4[0],   Points4[1],   Points4[2]]
SP14 = [Points4[150], Points4[151], Points4[152]]
SP24 = [Points4[300], Points4[301], Points4[302]]

CurrentPart.AddPoint('SP4',  SP4[0],  SP4[1],  SP4[2])
CurrentPart.AddPoint('SP14', SP14[0], SP14[1], SP14[2])
CurrentPart.AddPoint('SP24', SP24[0], SP24[1], SP24[2])

###############################################################################
# 5th Spline
###############################################################################
Path5 = CurrentPart.Add3DSketch('Spline5')
Points5 = []
for i in cycle:
    ix = i*3
    X15 = to_float4(Points_5[ix])
    Y15 = to_float4(Points_5[ix+1])
    Z15 = to_float4(Points_5[ix+2])
    Points5.extend([X15, Y15, Z15])

Path5.AddBspline(Points5)

SP5  = [Points5[0],   Points5[1],   Points5[2]]
SP15 = [Points5[150], Points5[151], Points5[152]]
SP25 = [Points5[300], Points5[301], Points5[302]]

CurrentPart.AddPoint('SP5',  SP5[0],  SP5[1],  SP5[2])
CurrentPart.AddPoint('SP15', SP15[0], SP15[1], SP15[2])
CurrentPart.AddPoint('SP25', SP25[0], SP25[1], SP25[2])

###############################################################################
# 6th Spline
###############################################################################
Path6 = CurrentPart.Add3DSketch('Spline6')
Points6 = []
for i in cycle:
    ix = i*3
    X16 = to_float4(Points_6[ix])
    Y16 = to_float4(Points_6[ix+1])
    Z16 = to_float4(Points_6[ix+2])
    Points6.extend([X16, Y16, Z16])

Path6.AddBspline(Points6)

SP6  = [Points6[0],   Points6[1],   Points6[2]]
SP16 = [Points6[150], Points6[151], Points6[152]]
SP26 = [Points6[300], Points6[301], Points6[302]]

CurrentPart.AddPoint('SP6',  SP6[0],  SP6[1],  SP6[2])
CurrentPart.AddPoint('SP16', SP16[0], SP16[1], SP16[2])
CurrentPart.AddPoint('SP26', SP26[0], SP26[1], SP26[2])

###############################################################################
# 7th Spline
###############################################################################
Path7 = CurrentPart.Add3DSketch('Spline7')
Points7 = []
for i in cycle:
    ix = i*3
    X17 = to_float4(Points_7[ix])
    Y17 = to_float4(Points_7[ix+1])
    Z17 = to_float4(Points_7[ix+2])
    Points7.extend([X17, Y17, Z17])

Path7.AddBspline(Points7)

SP7  = [Points7[0],   Points7[1],   Points7[2]]
SP17 = [Points7[150], Points7[151], Points7[152]]
SP27 = [Points7[300], Points7[301], Points7[302]]

CurrentPart.AddPoint('SP7',  SP7[0],  SP7[1],  SP7[2])
CurrentPart.AddPoint('SP17', SP17[0], SP17[1], SP17[2])
CurrentPart.AddPoint('SP27', SP27[0], SP27[1], SP27[2])

###############################################################################
# 8th Spline
###############################################################################
Path8 = CurrentPart.Add3DSketch('Spline8')
Points8 = []
for i in cycle:
    ix = i*3
    X18 = to_float4(Points_8[ix])
    Y18 = to_float4(Points_8[ix+1])
    Z18 = to_float4(Points_8[ix+2])
    Points8.extend([X18, Y18, Z18])

Path8.AddBspline(Points8)

SP8  = [Points8[0],   Points8[1],   Points8[2]]
SP18 = [Points8[150], Points8[151], Points8[152]]
SP28 = [Points8[300], Points8[301], Points8[302]]

CurrentPart.AddPoint('SP8',  SP8[0],  SP8[1],  SP8[2])
CurrentPart.AddPoint('SP18', SP18[0], SP18[1], SP18[2])
CurrentPart.AddPoint('SP28', SP28[0], SP28[1], SP28[2])

###############################################################################
# 9th Spline
###############################################################################
Path9 = CurrentPart.Add3DSketch('Spline9')
Points9 = []
for i in cycle:
    ix = i*3
    X19 = to_float4(Points_9[ix])
    Y19 = to_float4(Points_9[ix+1])
    Z19 = to_float4(Points_9[ix+2])
    Points9.extend([X19, Y19, Z19])

Path9.AddBspline(Points9)

SP9  = [Points9[0],   Points9[1],   Points9[2]]
SP19 = [Points9[150], Points9[151], Points9[152]]
SP29 = [Points9[300], Points9[301], Points9[302]]

CurrentPart.AddPoint('SP9',  SP9[0],  SP9[1],  SP9[2])
CurrentPart.AddPoint('SP19', SP19[0], SP19[1], SP19[2])
CurrentPart.AddPoint('SP29', SP29[0], SP29[1], SP29[2])

###############################################################################
# 10th Spline
###############################################################################
Path10 = CurrentPart.Add3DSketch('Spline10')
Points10 = []
for i in cycle:
    ix = i*3
    X110 = to_float4(Points_10[ix])
    Y110 = to_float4(Points_10[ix+1])
    Z110 = to_float4(Points_10[ix+2])
    Points10.extend([X110, Y110, Z110])

Path10.AddBspline(Points10)

SP10 = [Points10[0],   Points10[1],   Points10[2]]
SP20 = [Points10[150], Points10[151], Points10[152]]
SP30 = [Points10[300], Points10[301], Points10[302]]

CurrentPart.AddPoint('SP10', SP10[0], SP10[1], SP10[2])
CurrentPart.AddPoint('SP20', SP20[0], SP20[1], SP20[2])
CurrentPart.AddPoint('SP30', SP30[0], SP30[1], SP30[2])

###############################################################################
# Make Planes from Points
###############################################################################
Plane1 = CurrentPart.AddPlane('FirstPlane', SP1, SP2, SP3)
Plane2 = CurrentPart.AddPlane('MiddlePlane', SP11, SP12, SP13)
Plane3 = CurrentPart.AddPlane('LastPlane', SP21, SP22, SP23)

S1 = CurrentPart.AddSketch('FirstSketch',  Plane1)
S2 = CurrentPart.AddSketch('MiddleSketch', Plane2)
S3 = CurrentPart.AddSketch('LastSketch',   Plane3)

# Combine your first three sets into one set for each plane
First_Sketch = SP1 + SP2 + SP3 + SP4 + SP5 + SP6 + SP7 + SP8 + SP9 + SP10
Mid_Sketch   = SP11 + SP12 + SP13 + SP14 + SP15 + SP16 + SP17 + SP18 + SP19 + SP20
End_Sketch   = SP21 + SP22 + SP23 + SP24 + SP25 + SP26 + SP27 + SP28 + SP29 + SP30

print(First_Sketch)

###############################################################################
# Convert to local 2D coordinates and draw lines for each plane’s sketch
###############################################################################
SketchPoints_1 = []
SketchPoints_2 = []
SketchPoints_3 = []

# Each set (SP*) above has 10 triplets => 30 elements
def chunk_triplets(dat):
    return [dat[i:i+3] for i in range(0, len(dat), 3)]

# Convert First_Sketch
trip_1 = chunk_triplets(First_Sketch)  # 10 sets of [X,Y,Z]
for (xx, yy, zz) in trip_1:
    uv = S1.GlobaltoPoint(xx, yy, zz)
    SketchPoints_1.append(uv)

# Convert Mid_Sketch
trip_2 = chunk_triplets(Mid_Sketch)
for (xx, yy, zz) in trip_2:
    uv = S2.GlobaltoPoint(xx, yy, zz)
    SketchPoints_2.append(uv)

# Convert End_Sketch
trip_3 = chunk_triplets(End_Sketch)
for (xx, yy, zz) in trip_3:
    uv = S3.GlobaltoPoint(xx, yy, zz)
    SketchPoints_3.append(uv)

# Flatten so that AddLines(...) sees them as [x1,y1, x2,y2, x3,y3, ...]
def flatten_and_close(pts2d):
    flattened = []
    for xy in pts2d:
        flattened.append(xy[0])
        flattened.append(xy[1])
    # Close the profile: add the first point again
    flattened.append(flattened[0])
    flattened.append(flattened[1])
    return flattened

SketchPoints1 = flatten_and_close(SketchPoints_1)
SketchPoints2 = flatten_and_close(SketchPoints_2)
SketchPoints3 = flatten_and_close(SketchPoints_3)

S1.AddLines(SketchPoints1, False)
S2.AddLines(SketchPoints2, False)
S3.AddLines(SketchPoints3, False)
📢

Original source code with AI cleanup tasks applied

SplineScript_AI_Clean_01.py.txt

  • SplineScript_AI_Clean_01.py.txt

    import fpformat
    
    def read_input_file():
        """
        Prompts the user to select a 3D-points TXT file.
        Reads the file contents into a list of strings.
        Returns:
            txtfile (str): file path
            Points_Full (list of str): list of point coordinates as strings
        """
        Win = Windows()
        CurrentPartVar = CurrentPart()
    
        txtfile = Win.OpenFileDialog('Select 3D Pojnts in TXT,mm','TXT files(*.*)|*.txt*','.txt')
        f = open(txtfile, 'r')
        datareader2 = f.read()
        f.close()
    
        # Convert file lines into a list of coordinate strings
        data_into_list = datareader2.replace('\n', ',').split(',')
        Points_Full = data_into_list
    
        return txtfile, Points_Full
    
    def get_number_of_sections():
        """
        Prompts the user for the number of guide curves and returns it as an integer.
        """
        print 'Input Number of Guide Curves (typ - 10), then press ENTER'
        NumberOfSections = int(Read())
        return NumberOfSections
    
    def define_point_ranges(length):
        """
        Given the number of points (length) for each spline, 
        returns 10 range objects. This part remains 
        hard-coded to handle exactly 10 guide curves.
        """
        Points_1_range  = range(0, ((length*3)))
        Points_2_range  = range(length*3, ((3*2*length)))
        Points_3_range  = range((3*2*length), ((3*3*length)))
        Points_4_range  = range((3*3*length), ((3*4*length)))
        Points_5_range  = range((3*4*length), ((3*5*length)))
        Points_6_range  = range((3*5*length), ((3*6*length)))
        Points_7_range  = range((3*6*length), ((3*7*length)))
        Points_8_range  = range((3*7*length), ((3*8*length)))
        Points_9_range  = range((3*8*length), ((3*9*length)))
        Points_10_range = range((3*9*length), ((3*10*length)))
        
        return (
            Points_1_range, Points_2_range, Points_3_range,
            Points_4_range, Points_5_range, Points_6_range,
            Points_7_range, Points_8_range, Points_9_range,
            Points_10_range
        )
    
    def extract_float_points(Points_Full, index_range):
        """
        Converts a sub-range of Points_Full into a list of floats.
        """
        return [float(Points_Full[i]) for i in index_range]
    
    def create_spline_sketch(sketch_name, float_points):
        """
        Creates a 3D sketch for a spline:
        - Loops over the float_points in sets of three,
          fixes them to 4 decimals, and accumulates them.
        - Adds a B-spline to the sketch.
        - Returns (Path object, some sample points) for plane creation, etc.
        """
        Path = CurrentPart().Add3DSketch(sketch_name)
        PointsList = []
        cycle = range(len(float_points)//3)
    
        # Build the array for AddBspline
        for aaa in cycle:
            IncX = aaa * 3
            IncY = (aaa*3) + 1
            IncZ = (aaa*3) + 2
            
            X_val = fpformat.fix(float_points[IncX], 4)
            Y_val = fpformat.fix(float_points[IncY], 4)
            Z_val = fpformat.fix(float_points[IncZ], 4)
            
            PointsList.extend([X_val, Y_val, Z_val])
        
        # Create the B-spline from the points
        Path.AddBspline(PointsList)
        
        # Return sample points for plane references (SP, SP1, SP2 etc.)
        # Hard-coded offsets: 0, 150, 300 (just as in the original).
        # Note: Make sure the float_points array has enough points.
        SP  = [
            fpformat.fix(float(PointsList[0]),4),
            fpformat.fix(float(PointsList[1]),4),
            fpformat.fix(float(PointsList[2]),4)
        ]
        SP1 = [
            fpformat.fix(float(PointsList[150]),4),
            fpformat.fix(float(PointsList[151]),4),
            fpformat.fix(float(PointsList[152]),4)
        ]
        SP2 = [
            fpformat.fix(float(PointsList[300]),4),
            fpformat.fix(float(PointsList[301]),4),
            fpformat.fix(float(PointsList[302]),4)
        ]
        
        return Path, SP, SP1, SP2
    
    def create_reference_points_on_part(SP_name, sp_coords):
        """
        Adds a reference point in the current part at the location of sp_coords.
        sp_coords should be [x, y, z] as strings or floats convertible to strings.
        """
        # Convert each to float if needed, then fix to 4 decimals again
        x_str = fpformat.fix(float(sp_coords[0]),4)
        y_str = fpformat.fix(float(sp_coords[1]),4)
        z_str = fpformat.fix(float(sp_coords[2]),4)
        CurrentPart().AddPoint(SP_name, [x_str, y_str, z_str])
    
    def create_planes_and_sketches(SP1, SP2, SP3, SP11, SP12, SP13, SP21, SP22, SP23):
        """
        Creates 3 planes from sets of points:
            Plane1 from SP1, SP2, SP3
            Plane2 from SP11, SP12, SP13
            Plane3 from SP21, SP22, SP23
        Then creates 2D sketches (S1, S2, S3) on those planes.
        Returns:
            (Plane1, Plane2, Plane3, S1, S2, S3)
        """
        Plane1 = CurrentPart().AddPlane('FirstPlane',  SP1,  SP2,  SP3)
        Plane2 = CurrentPart().AddPlane('MiddlePlane', SP11, SP12, SP13)
        Plane3 = CurrentPart().AddPlane('LastPlane',   SP21, SP22, SP23)
        
        S1 = CurrentPart().AddSketch('FirstSketch',  Plane1)
        S2 = CurrentPart().AddSketch('MiddleSketch', Plane2)
        S3 = CurrentPart().AddSketch('LastSketch',   Plane3)
        
        return Plane1, Plane2, Plane3, S1, S2, S3
    
    def create_2D_points_and_lines(S1, S2, S3, First_Sketch, Mid_Sketch, End_Sketch):
        """
        Takes the 3 sets of global points (First_Sketch, Mid_Sketch, End_Sketch),
        projects them onto the local plane sketches (S1, S2, S3),
        then adds lines connecting them in each 2D sketch.
        """
        SketchPoints_1 = []
        SketchPoints_2 = []
        SketchPoints_3 = []
    
        # Project 10 sets of points into S1
        for aaa in range(10):
            IncX = aaa*3
            IncY = (aaa*3)+1
            IncZ = (aaa*3)+2
            
            X11 = First_Sketch[IncX]
            Y11 = First_Sketch[IncY]
            Z11 = First_Sketch[IncZ]
            
            UV1 = S1.GlobaltoPoint(X11, Y11, Z11)
            SketchPoints_1.append(UV1)
    
        # Project 10 sets of points into S2
        for bbb in range(10):
            IncX = bbb*3
            IncY = (bbb*3)+1
            IncZ = (bbb*3)+2
            
            X22 = fpformat.fix(float(Mid_Sketch[IncX]),4)
            Y22 = fpformat.fix(float(Mid_Sketch[IncY]),4)
            Z22 = fpformat.fix(float(Mid_Sketch[IncZ]),4)
            
            UV2 = S2.GlobaltoPoint(X22, Y22, Z22)
            SketchPoints_2.append(UV2)
    
        # Project 10 sets of points into S3
        for ccc in range(10):
            IncX = ccc*3
            IncY = (ccc*3)+1
            IncZ = (ccc*3)+2
            
            X33 = fpformat.fix(float(End_Sketch[IncX]),4)
            Y33 = fpformat.fix(float(End_Sketch[IncY]),4)
            Z33 = fpformat.fix(float(End_Sketch[IncZ]),4)
            
            UV3 = S3.GlobaltoPoint(X33, Y33, Z33)
            SketchPoints_3.append(UV3)
    
        # Flatten the lists for AddLines(), and repeat the first point to close
        SketchPoints1 = [element for innerList in SketchPoints_1 for element in innerList]
        SketchPoints1.extend([SketchPoints1[0], SketchPoints1[1]])
    
        SketchPoints2 = [element for innerList in SketchPoints_2 for element in innerList]
        SketchPoints2.extend([SketchPoints2[0], SketchPoints2[1]])
    
        SketchPoints3 = [element for innerList in SketchPoints_3 for element in innerList]
        SketchPoints3.extend([SketchPoints3[0], SketchPoints3[1]])
    
        # Finally, add lines to each sketch
        S1.AddLines(SketchPoints1, False)
        S2.AddLines(SketchPoints2, False)
        S3.AddLines(SketchPoints3, False)
    
    def main():
        # -------------------
        # Step 1: Read file and parse data
        # -------------------
        txtfile, Points_Full = read_input_file()
        NumberOfSections = get_number_of_sections()
    
        length = (len(Points_Full)/(NumberOfSections*3))
        print(length)  # Just to match the original code's debug
    
        # -------------------
        # Step 2: Define index ranges for each group
        # -------------------
        (Points_1_range, Points_2_range, Points_3_range,
         Points_4_range, Points_5_range, Points_6_range,
         Points_7_range, Points_8_range, Points_9_range,
         Points_10_range) = define_point_ranges(length)
    
        # -------------------
        # Step 3: Build float-lists for each group
        # -------------------
        Points_1  = extract_float_points(Points_Full, Points_1_range)
        Points_2  = extract_float_points(Points_Full, Points_2_range)
        Points_3  = extract_float_points(Points_Full, Points_3_range)
        Points_4  = extract_float_points(Points_Full, Points_4_range)
        Points_5  = extract_float_points(Points_Full, Points_5_range)
        Points_6  = extract_float_points(Points_Full, Points_6_range)
        Points_7  = extract_float_points(Points_Full, Points_7_range)
        Points_8  = extract_float_points(Points_Full, Points_8_range)
        Points_9  = extract_float_points(Points_Full, Points_9_range)
        Points_10 = extract_float_points(Points_Full, Points_10_range)
    
        # -------------------
        # Step 4: Create 3D splines (Paths) from each group
        #         Also add reference points for each set
        # -------------------
        Path1,  SP1,  SP11,  SP21  = create_spline_sketch('Spline1',  Points_1)
        Path2,  SP2,  SP12,  SP22  = create_spline_sketch('Spline2',  Points_2)
        Path3,  SP3,  SP13,  SP23  = create_spline_sketch('Spline3',  Points_3)
        Path4,  SP4,  SP14,  SP24  = create_spline_sketch('Spline4',  Points_4)
        Path5,  SP5,  SP15,  SP25  = create_spline_sketch('Spline5',  Points_5)
        Path6,  SP6,  SP16,  SP26  = create_spline_sketch('Spline6',  Points_6)
        Path7,  SP7,  SP17,  SP27  = create_spline_sketch('Spline7',  Points_7)
        Path8,  SP8,  SP18,  SP28  = create_spline_sketch('Spline8',  Points_8)
        Path9,  SP9,  SP19,  SP29  = create_spline_sketch('Spline9',  Points_9)
        Path10, SP10, SP20,  SP30  = create_spline_sketch('Spline10', Points_10)
    
        # Add those reference points in the current part (SP1, SP11, etc.)
        # Original code: CurrentPart.AddPoint('SP1', SP1) ...
        # Here we simply replicate it in a small loop:
        create_reference_points_on_part('SP1',  SP1)
        create_reference_points_on_part('SP11', SP11)
        create_reference_points_on_part('SP21', SP21)
    
        create_reference_points_on_part('SP2',  SP2)
        create_reference_points_on_part('SP12', SP12)
        create_reference_points_on_part('SP22', SP22)
    
        create_reference_points_on_part('SP3',  SP3)
        create_reference_points_on_part('SP13', SP13)
        create_reference_points_on_part('SP23', SP23)
    
        create_reference_points_on_part('SP4',  SP4)
        create_reference_points_on_part('SP14', SP14)
        create_reference_points_on_part('SP24', SP24)
    
        create_reference_points_on_part('SP5',  SP5)
        create_reference_points_on_part('SP15', SP15)
        create_reference_points_on_part('SP25', SP25)
    
        create_reference_points_on_part('SP6',  SP6)
        create_reference_points_on_part('SP16', SP16)
        create_reference_points_on_part('SP26', SP26)
    
        create_reference_points_on_part('SP7',  SP7)
        create_reference_points_on_part('SP17', SP17)
        create_reference_points_on_part('SP27', SP27)
    
        create_reference_points_on_part('SP8',  SP8)
        create_reference_points_on_part('SP18', SP18)
        create_reference_points_on_part('SP28', SP28)
    
        create_reference_points_on_part('SP9',  SP9)
        create_reference_points_on_part('SP19', SP19)
        create_reference_points_on_part('SP29', SP29)
    
        create_reference_points_on_part('SP10', SP10)
        create_reference_points_on_part('SP20', SP20)
        create_reference_points_on_part('SP30', SP30)
    
        # -------------------
        # Step 5: Make Planes from the first, middle, last points 
        #         across the first 3 splines
        #         (Matches your original code exactly)
        # -------------------
        (Plane1, Plane2, Plane3, 
         S1, S2, S3) = create_planes_and_sketches(SP1, SP2, SP3,
                                                 SP11, SP12, SP13,
                                                 SP21, SP22, SP23)
    
        # -------------------
        # Step 6: Create point lists for 2D sketches (First, Mid, End)
        #         Then project them onto the sketches as lines
        # -------------------
        First_Sketch = SP1 + SP2 + SP3 + SP4 + SP5 + SP6 + SP7 + SP8 + SP9 + SP10
        Mid_Sketch   = SP11 + SP12 + SP13 + SP14 + SP15 + SP16 + SP17 + SP18 + SP19 + SP20
        End_Sketch   = SP21 + SP22 + SP23 + SP24 + SP25 + SP26 + SP27 + SP28 + SP29 + SP30
    
        print(First_Sketch)  # Matches original code
    
        create_2D_points_and_lines(S1, S2, S3, First_Sketch, Mid_Sketch, End_Sketch)
    
    # -------------------------------
    # Entry Point
    # -------------------------------
    main()
    >>>
    Input Number of Guide Curves (typ - 10), then press ENTER
    10
    101
    ['1224.7348', '1039.3295', '173.5912', '1219.8444', '1041.3338', '172.0690', '1219.7922', '1046.2421', '178.6999', '1216.2133', '1047.7089', '177.5859', '1216.1981', '1049.1405', '179.5199', '1217.8986', '1048.4435', '180.0492', '1217.9008', '1048.2390', '179.7730', '1222.9689', '1046.1618', '181.3505', '1222.9668', '1046.3663', '181.6267', '1224.6673', '1045.6693', '182.1560']
    Traceback (most recent call last):
      File "<string>", line 322, in <module>
      File "<string>", line 316, in main
      File "<string>", line 162, in create_2D_points_and_lines
    TypeError: expected float, got str
    >>>
    
📎

davex7637.AD_PKG

Random Hole in block

ID: A7246742B-9 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 11, 2025 5:57 AM AI summary: The code creates a rectangular block with dimensions 40×20×10 mm and cuts a circular hole at a random position on the top face, ensuring the hole remains within the block's boundaries.

import random

def random_hole_in_block():
    """
    Creates a rectangular block (40 × 20 × 10) and cuts a circular hole 
    at a random position on the top face.
    """
    # 1. Create a part
    MyPart = Part("RandomHoleBlock")

    # 2. Add a sketch for the rectangle on the XY-plane
    XYPlane = MyPart.GetPlane("XY-Plane")
    RectSketch = MyPart.AddSketch("RectSketch", XYPlane)
    # Make a 40 × 20 rectangle
    width = 40.0
    height = 20.0
    RectSketch.AddRectangle(0.0, 0.0, width, height, False)

    # 3. Extrude the rectangle up to 10 mm
    MyPart.AddExtrudeBoss("Block", RectSketch, 10.0, False)

    # 4. Identify the top face (the face created by the extrusion). 
    #    Typically, after an extrude, the top might be "Face<5>", "Face<6>", etc.
    #    If uncertain, you can list all faces to see which one matches:
    # faces = MyPart.GetFaces()
    # for i, f in enumerate(faces):
    #     print(i, f.Name, f.GetArea())

    # For demonstration, let's assume "Face<5>" is the top. 
    # (Alternatively, you could systematically find the largest area face 
    # above the XY-plane, etc.)
    TopFace = MyPart.GetFace("Face<5>")

    # 5. Create a new sketch on the top face
    HoleSketch = MyPart.AddSketch("RandomHoleSketch", TopFace)

    # 6. Generate random coordinates for the circle center 
    #    ensuring it stays well inside the block. 
    #    We'll pick a circle radius of, say, 4 mm.
    hole_radius = 4.0

    # we want to keep the circle fully within the 40×20 region:
    #   valid x range: [hole_radius, width - hole_radius]
    #   valid y range: [hole_radius, height - hole_radius]
    x_min = hole_radius
    x_max = width - hole_radius
    y_min = hole_radius
    y_max = height - hole_radius

    center_x = random.uniform(x_min, x_max)
    center_y = random.uniform(y_min, y_max)

    # 7. Add the circle to the sketch
    HoleSketch.AddCircle(center_x, center_y, hole_radius * 2.0, False)  # diameter = 2×radius

    # 8. Extrude cut that circle "Through All"
    MyPart.AddExtrudeCut("RandomHole", 
                         HoleSketch, 
                         0.0, 
                         False, 
                         Part.EndCondition.ThroughAll, 
                         None, 
                         0.0, 
                         Part.DirectionType.Normal, 
                         None, 
                         0.0, 
                         False)

    # Info
    print("Block created with size 40×20×10 mm.")
    print("Cut a hole at random position (x={:.2f}, y={:.2f}), radius={:.2f}".format(
        center_x, center_y, hole_radius
    ))

# Uncomment this line to run directly:
random_hole_in_block()

Reference Geometry Showcase

ID: A7246742B-13 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 11, 2025 9:00 AM AI summary: Python code for creating a reference geometry showcase includes steps to create a block, add an angled plane, define a plane from three points, and establish an intersection axis, avoiding parallel-plane errors.

def reference_geometry_showcase_fixed():
    """
    Similar to your original code, but the second plane is angled 
    so it properly intersects XY-plane (instead of being parallel).
    """
    part_obj = Part("ReferenceGeometryShowcaseFixed")

    # Step 1: Create a 40×20×10 block
    xy_plane = part_obj.GetPlane("XY-Plane")
    base_sketch = part_obj.AddSketch("BaseSketch", xy_plane)
    base_sketch.AddRectangle(0, 0, 40, 20, False)
    part_obj.AddExtrudeBoss("BaseExtrusion", base_sketch, 10, False)
    print("Step 1: Created a 40×20×10 block.")

    # Instead of an offset plane, create a plane at a 30-degree angle from XY-plane around the Y-axis
    # 1) Get the Y-axis as the rotation axis
    y_axis = part_obj.YAxis   # (language independent property)
    # 2) Add the angled plane
    plane_with_angle = part_obj.AddPlane("PlaneAngleXY", xy_plane, y_axis, 30.0)
    print("Step 2: Added plane 'PlaneAngleXY' at 30 degrees to XY-plane.")

    # Step 3: Plane from three 3D points
    #   (Same as before, corners of block)
    ptA = part_obj.AddPoint("CornerA", 0, 0, 0)
    ptB = part_obj.AddPoint("CornerB", 40, 0, 0)
    ptC = part_obj.AddPoint("CornerC", 0, 0, 10)
    plane3Points = part_obj.AddPlane("PlaneFrom3Points",
                                     [0, 0, 0],
                                     [40, 0, 0],
                                     [0, 0, 10])
    print("Step 3: Created 'PlaneFrom3Points' using three 3D coords.")

    # Step 4: Axis from the intersection of XY-plane and plane_with_angle
    #   This time they are not parallel, so we get a valid axis
    axis_intersect = part_obj.AddAxis("AxisXYandAngle",
                                      xy_plane,
                                      plane_with_angle)
    print("Step 4: Created axis 'AxisXYandAngle' from intersection of XY-plane and 'PlaneAngleXY'.")

    # You can then continue with your other steps (e.g., axis from two points, plane from offset, etc.)
    # Just remember: if you create an offset plane from XY-plane, that new plane remains parallel. 
    # So don't attempt intersection with XY-plane again unless you want an error.

    print("All done without the parallel-plane intersection error!")

image.png

SimpleEE (Simple Equation Editor)

ID: A7246742B-23 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: February 7, 2025 11:01 PM AI summary: A dynamic equation editor for Alibre Script allows users to edit parameters in real-time within an active part window, handling equations and numeric values while regenerating the part upon changes.

#===========================================================
# AlibreScript: Dynamic Equation Editor (using CurrentPart)
#===========================================================
#
# Provides a simple “equation editor” style UI for the currently
# active/open part window.  Lists all parameters, lets the
# user edit each parameter’s equation (or numeric value),
# and regenerates in real time upon each edit.
#
# NOTES / LIMITATIONS:
#  1) Must have a part window active so that CurrentPart() is valid.
#  2) If a parameter has no equation, we display its numeric value
#     as a string. Otherwise, we display its .Equation text.
#  3) When user changes the text, we first try assigning
#     param.Equation = newText. If it fails, we next try numeric .Value.
#  4) A more robust script might handle invalid expressions more gracefully.
#  5) This script is entirely “flat”: no class or advanced function usage,
#     except the minimal callback functions for the dialog events.
#  6) Requires AlibreScript with Windows() / UtilityDialog capabilities
#
#===========================================================

# Step 1: Get the current part
TargetPart = CurrentPart()
Units.Current = UnitTypes.Inches
if TargetPart is None:
    sys.exit("No current part window found. Please open a part and try again.")

# Step 2: Gather all parameters
AllParams = TargetPart.Parameters
if len(AllParams) == 0:
    sys.exit("The current part has no parameters defined.")

# Step 3: Build input lines for the UtilityDialog
DialogInputs = []
ParamIndexMap = []  # store index -> parameter

for idx, param in enumerate(AllParams):
    if param.Equation and len(param.Equation.strip()) > 0:
        defaultText = param.Equation
    else:
        defaultText = str(param.Value)

    DialogInputs.append([param.Name, WindowsInputTypes.String, defaultText])
    ParamIndexMap.append(param)

# Step 4: Define the realtime input-changed callback
def InputChangedCallback(InputIndex, NewValue):
    changedParam = ParamIndexMap[InputIndex]
    text = NewValue.strip()

    # Try setting the equation
    try:
        changedParam.Equation = text
    except:
        # If that fails, try numeric
        try:
            numericVal = float(text)
            changedParam.Equation = ""
            changedParam.Value = numericVal
        except:
            Win.ErrorDialog("Invalid expression or number: '%s'" % text,
                            "Parameter Update Error")
            return

    # Regenerate part
    TargetPart.Regenerate()

# Step 5: Action button callback
def ActionButtonCallback(ValuesList):
    # Apply all values before closing
    TargetPart.Regenerate()

# Step 6: Show the UtilityDialog
Win = Windows()
Win.UtilityDialog(
    "SimpleEE",
    "Regenerate",
    ActionButtonCallback,
    InputChangedCallback,
    DialogInputs,
    500
)

SimpleEE.gif

SimpleEE (Simple Equation Editor) 2

ID: A7246742B-24 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: February 7, 2025 11:02 PM AI summary: A Python script for a Simple Equation Editor allows users to set parameters for a part in inches, with a dialog for inputting size options and real-time updates to equations or numeric values, including error handling for invalid inputs.

def main():
    TargetPart = CurrentPart()
    Units.Current = UnitTypes.Inches
    if TargetPart is None:
        sys.exit("No current part window found. Please open a part and try again.")

    all_params = TargetPart.Parameters
    if len(all_params) == 0:
        sys.exit("The current part has no parameters defined.")

    # -------------------------------------------------
    # 1) Updated list of desired sizes
    # -------------------------------------------------
    size_options = [
        "0.13",
        "0.25",
        "0.38",
        "0.50",
        "0.63",
        "0.75",
        "0.88",
        "1.00",
        "1.13",
        "1.25",
        "1.38",
        "1.50",
        "1.63",
        "1.75",
        "1.88",
        "2.00",
        "2.13",
        "2.25",
        "2.38",
        "2.50",
        "2.63",
        "2.75",
        "2.88",
        "3.00",
        "3.13",
        "3.25",
        "3.38",
        "3.50",
        "3.63",
        "3.75",
        "3.88",
        "4.00",
        "4.13",
        "4.25",
        "4.38",
        "4.50",
        "4.63",
        "4.75",
        "4.88",
        "5.00",
        "5.13",
        "5.25",
        "5.38",
        "5.50",
        "5.63",
        "5.75",
        "5.88",
        "6.00",
        "6.13",
        "6.25",
        "6.38",
        "6.50",
        "6.63",
        "6.75",
        "6.88",
        "7.00",
        "7.13",
        "7.25",
        "7.38",
        "7.50",
        "7.63",
        "7.75",
        "7.88",
        "8.00",
        "8.13",
        "8.25",
        "8.38",
        "8.50",
        "8.63",
        "8.75",
        "8.88",
        "9.00",
        "9.13",
        "9.25",
        "9.38",
        "9.50",
        "9.63",
        "9.75",
        "9.88",
        "10.00",
        "10.13",
        "10.25",
        "10.38",
        "10.50",
        "10.63",
        "10.75",
        "10.88",
        "11.00"
    ]

    dialog_inputs = []
    param_index_map = []

    # -------------------------------------------------
    # Build the dialog inputs for each parameter
    # -------------------------------------------------
    for param in all_params:
        # Figure out the parameter's current text (equation or numeric)
        try:
            if param.Equation and len(param.Equation.strip()) > 0:
                default_text = param.Equation.strip()
            else:
                default_text = str(param.Value)
        except:
            # Skip weird/invalid parameters
            continue

        # Make a copy of size_options (so we don't mutate the original)
        custom_list = size_options[:]

        # Ensure the parameter's current value is in the list
        if default_text not in custom_list:
            custom_list.append(default_text)

        # Find the default index
        default_index = custom_list.index(default_text)

        # Append [Name, WindowsInputTypes.StringList, list_of_strings, default_index]
        dialog_inputs.append([
            param.Name,
            WindowsInputTypes.StringList,
            custom_list,
            default_index
        ])
        param_index_map.append(param)

    if not dialog_inputs:
        sys.exit("No valid parameters found.")

    # -------------------------------------------------
    # Real-time "changed" callback
    # -------------------------------------------------
    def input_changed_callback(input_index, new_value):
        changed_param = param_index_map[input_index]

        # Retrieve the list of choices for this input row (3rd item)
        choice_list = dialog_inputs[input_index][2]

        # Determine if new_value is an integer (index) or already a string
        if isinstance(new_value, int):
            # new_value is an index
            if new_value < 0 or new_value >= len(choice_list):
                Win.ErrorDialog("Index out of range: {}".format(new_value),
                                "Parameter Update Error")
                return
            text = choice_list[new_value].strip()
        else:
            # new_value is likely a string
            text = str(new_value).strip()

        # First, try to assign as an Equation
        try:
            changed_param.Equation = text
        except:
            # Fallback: numeric
            try:
                numeric_val = float(text)
                changed_param.Equation = ""
                changed_param.Value = numeric_val
            except:
                Win.ErrorDialog(
                    "Could not set parameter '{}' to '{}'.\n"
                    "Neither a valid equation nor a valid number."
                    .format(changed_param.Name, text),
                    "Parameter Update Error"
                )
                return

        # Regenerate the part
        try:
            TargetPart.Regenerate()
        except:
            Win.ErrorDialog(
                "Error regenerating part after setting '{}'."
                .format(changed_param.Name),
                "Regeneration Error"
            )

    # -------------------------------------------------
    # "Regenerate" button callback
    # -------------------------------------------------
    def action_button_callback(values_list):
        try:
            TargetPart.Regenerate()
        except:
            Win.ErrorDialog("Error regenerating part on final apply.",
                            "Regeneration Error")

    # -------------------------------------------------
    # Show the dialog
    # -------------------------------------------------
    Win = Windows()
    Win.UtilityDialog(
        "SimpleEE 2",
        "Regenerate",
        action_button_callback,
        input_changed_callback,
        dialog_inputs,
        500
    )

# Finally, call main()
main()

SimpleEE 2.gif

SimpleEE (Simple Equation Editor) 3

ID: A7246742B-33 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: June 18, 2025 9:41 PM AI summary: Dynamic Equation Editor in Python for Alibre Script allows real-time updates of parameter equations and values, with error handling for invalid inputs and a user-friendly interface for input changes.

#===========================================================
#  Dynamic Equation Editor – refresh-enabled version
#===========================================================

import sys
TargetPart = CurrentPart()
Units.Current = UnitTypes.Inches
if TargetPart is None:
    sys.exit("No current part window found. Please open a part and try again.")

AllParams = TargetPart.Parameters
if len(AllParams) == 0:
    sys.exit("The current part has no parameters defined.")

DialogInputs   = []
ParamIndexMap  = []

for p in AllParams:
    DialogInputs.append([
        p.Name,
        WindowsInputTypes.String,
        p.Equation.strip() if p.Equation else str(p.Value)
    ])
    ParamIndexMap.append(p)

# ---------- helpers ----------------------------------------------------------
_prog_update = False          # prevents infinite callback recursion

def RefreshDialog(exclude=None):
    """Push the latest equation/value of every parameter into its textbox."""
    global _prog_update
    _prog_update = True
    for i, prm in enumerate(ParamIndexMap):
        if i == exclude:       # leave the box the user is typing in untouched
            continue
        txt = prm.Equation.strip() if prm.Equation else str(prm.Value)
        Win.SetInputValue(i, txt)    # << the magic sync call
    _prog_update = False
# -----------------------------------------------------------------------------

def InputChangedCallback(InputIndex, NewValue):
    if _prog_update:           # ignore programmatic updates
        return

    prm  = ParamIndexMap[InputIndex]
    text = NewValue.strip()

    try:                       # 1) try equation
        prm.Equation = text
    except:
        try:                   # 2) try numeric literal
            prm.Equation = ""
            prm.Value    = float(text)
        except:
            Win.ErrorDialog("Invalid expression or number: '%s'" % text,
                            "Parameter Update Error")
            RefreshDialog(exclude=InputIndex)   # roll back visible value
            return

    TargetPart.Regenerate()
    RefreshDialog(exclude=InputIndex)           # show new driven values

def ActionButtonCallback(vals):
    TargetPart.Regenerate()
    RefreshDialog()                              # full refresh

Win = Windows()
Win.UtilityDialog(
    "SimpleEE",
    "Regenerate",
    ActionButtonCallback,
    InputChangedCallback,
    DialogInputs,
    500
)

Sweep Stair Beam Sketch

ID: A7246742B-34 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPTPro Model: o1 By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: July 9, 2025 4:58 AM AI summary: Python code for creating a sweep stair beam with valid geometry using Alibre Script and IronPython, including path definition, unit direction vector computation, profile plane creation, and sweep feature addition.

# Corrected Sweep Stair Beam with Valid Geometry
P = Part("StairBeamFixed")

# Define 3D sweep path (gentle incline)
Path = P.Add3DSketch("SweepPath")
Path.AddLines([0, 0, 0, 3000, 3000, 0])

# Compute unit direction vector of the path
import math
dx = 3000 - 0
dy = 3000 - 0
dz = 0 - 0
length = math.sqrt(dx**2 + dy**2 + dz**2)
nx = dx / length
ny = dy / length
nz = dz / length

# Create profile plane perpendicular to path
Pln = P.AddPlane("StartProfilePlane", [nx, ny, nz], [0, 0, 0])

# Profile Sketch
S = P.AddSketch("Profile", Pln)
S.AddRectangle(-75, -10, 75, 10, False)

# Sweep Feature
P.AddSweepBoss("BeamSweep", S, Path, False, Part.EndCondition.EntirePath, None, 0, 0, False)

valid chamfer

ID: A7246742B-6 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 11, 2025 5:20 AM AI summary: A Python script demonstrates creating a rectangular part, extruding it, and applying a chamfer to a specified edge using Alibre Script and IronPython2.7.

def valid_chamfer_example():
    # Create part
    part_obj = Part("BlockForChamfer")

    # Create a simple rectangle on XY-plane
    xyplane = part_obj.GetPlane("XY-Plane")
    sketch = part_obj.AddSketch("BlockSketch", xyplane)
    # 40 × 20 rectangle
    sketch.AddRectangle(0, 0, 40, 20, False)

    # Extrude 10 mm tall
    part_obj.AddExtrudeBoss("BlockExtrusion", sketch, 10, False)

    # Let's see which edges we have
    # Typically the "vertical" edges from the extrusion or the rectangle boundary might be Edge<1..> etc.
    edges = part_obj.GetEdges()
    for i, e in enumerate(edges):
        print(i, e.Name, e.Length)

    # Suppose from printing, we find the top rectangle edges are Edge<5>, Edge<6>, Edge<7>, Edge<8>.
    # We can pick one to chamfer that is definitely a sharp top edge. For example:
    edge_name_to_chamfer = "Edge<6>"
    chamfer_edge = part_obj.GetEdge(edge_name_to_chamfer)

    # Apply a chamfer of 2 mm
    part_obj.AddChamfer("MyChamfer", chamfer_edge, 2.0, False)
    print("Chamfer succeeded on a valid sharp edge:", edge_name_to_chamfer)

valid_chamfer_example()

valid fillet

ID: A7246742B-10 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 11, 2025 6:00 AM AI summary: Example code demonstrates creating a rectangular part, extruding it, enumerating edges, and applying a 2 mm fillet to a specified sharp edge in Alibre Script using IronPython.

def valid_fillet_example():
    # Create a new part named "BlockForFillet"
    part_obj = Part("BlockForFillet")

    # Create a simple rectangle on the XY-plane
    xy_plane = part_obj.GetPlane("XY-Plane")
    sketch = part_obj.AddSketch("SketchBlock", xy_plane)
    # 40×20 rectangle
    sketch.AddRectangle(0, 0, 40, 20, False)
    
    # Extrude the rectangle to 10 mm height
    part_obj.AddExtrudeBoss("BlockExtrusion", sketch, 10, False)

    # Enumerate edges to see what edges exist
    edges = part_obj.GetEdges()
    for i, e in enumerate(edges):
        print("Index:", i, "Name:", e.Name, "Length:", e.Length)

    # Suppose from the printout, we see that the top edges might be Edge<5>, Edge<6>, etc.
    # We'll pick one edge that is definitely a sharp top edge:
    edge_name_to_fillet = "Edge<6>"
    target_edge = part_obj.GetEdge(edge_name_to_fillet)

    # Apply a constant fillet of 2 mm to that sharp edge
    part_obj.AddFillet("MyFillet", target_edge, 2.0, False)
    print("Fillet succeeded on a valid sharp edge:", edge_name_to_fillet)

# Example usage:
valid_fillet_example()

Window Showcase

ID: A7246742B-14 Programming Language: Alibre Script, IronPython2.7 LLM or AI Product: CustomChatGPT By StephenBot: No Status: Done Category: Testbed Reviewed: No Created time: January 11, 2025 9:10 AM AI summary: Demonstrates various dialog windows in Alibre Script, including info, error, question, options, utility, open file, save file, and folder selection dialogs, with user interaction and callbacks.

def windows_showcase():
    """
    Demonstrates multiple dialog windows using the Windows object.
    1) InfoDialog
    2) ErrorDialog
    3) QuestionDialog
    4) OptionsDialog
    5) UtilityDialog
    6) OpenFileDialog
    7) SaveFileDialog
    8) SelectFolderDialog
    """
    import sys

    # Create a Windows object for dialogs
    Win = Windows()
    
    # 1) Show an info dialog
    Win.InfoDialog("This is an information message.", "Information")
    
    # 2) Show an error dialog
    Win.ErrorDialog("Uh oh, something happened!", "Error")
    
    # 3) Show a question dialog (returns True for 'yes', False for 'no')
    user_chose_yes = Win.QuestionDialog("Do you want to proceed?", "Question")
    if user_chose_yes:
        print("User clicked Yes.")
    else:
        print("User clicked No.")
    
    # 4) Show an OptionsDialog for multiple inputs
    #    Each item is [Name, WindowsInputTypes, DefaultValue, ...]
    opts = []
    opts.append(["Name", WindowsInputTypes.String, "Unnamed"])
    opts.append(["Thickness (mm)", WindowsInputTypes.Real, 5.0])
    opts.append(["IncludeHoles?", WindowsInputTypes.Boolean, True])
    opts.append(["Quantity", WindowsInputTypes.Integer, 10])
    opts.append(["Material", WindowsInputTypes.StringList, ["Plastic", "Steel", "Aluminum"], "Steel"])
    
    user_values = Win.OptionsDialog("Enter Values", opts)
    if user_values is None:
        print("User canceled the OptionsDialog.")
    else:
        print("User values from OptionsDialog: {}".format(user_values))
    
    # 5) Show a UtilityDialog that remains open, with a single real input
    #    We'll create a function callback that is invoked each time the user 
    #    changes input or presses the action button.
    def on_apply_clicked(vals):
        print("Action button clicked, user entries: {}".format(vals))

    def input_changed_callback(index, value):
        print("Input at index {} changed to: {}".format(index, value))
    
    # The UtilityDialog inputs: 
    #   e.g. [ ["NameOfInput", WindowsInputTypes.Real, 1.234], ...]
    utility_inputs = [
        ["Angle", WindowsInputTypes.Real, 45.0],
        ["CheckBox", WindowsInputTypes.Boolean, True],
    ]
    
    # Show the dialog
    # Parameters: Title, ActionButtonText, ActionButtonCallback, 
    #             InputChangedCallback, InputsList, InputAreaWidth=200
    Win.UtilityDialog(
        "UtilityDialog Showcase", 
        "Apply", 
        on_apply_clicked,
        input_changed_callback,
        utility_inputs,
        250   # width of input area
    )
    # The script continues after the user closes the UtilityDialog.
    
    # 6) Prompt user to open a file. 
    file_path = Win.OpenFileDialog("Select a file", "All Files|*.*", ".txt")
    if file_path:
        print("File chosen: {}".format(file_path))
    else:
        print("User canceled open file dialog.")
    
    # 7) Prompt user to save a file
    save_path = Win.SaveFileDialog("Save your file", "Text Files|*.txt|All Files|*.*", ".txt")
    if save_path:
        print("File to save: {}".format(save_path))
    else:
        print("User canceled save file dialog.")
    
    # 8) Prompt user to select a folder
    folder_path = Win.SelectFolderDialog("", "Choose a folder for something")
    if folder_path:
        print("Folder chosen: {}".format(folder_path))
    else:
        print("User canceled folder selection.")

    print("Finished the Windows showcase.")

# To run directly in AlibreScript, just call:
# windows_showcase()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment