# Joint Creator This script can be used to create joints between two parts that share coincident space.

1) Open a New Assembly workspace and insert two parts to be used for the Joint Creator script.  *Note these must be two separate parts and not two instances of the same part.

2) Use the Constraint tool to align the parts appropriately so that they occupy coincident space and are flush with one another in the area of the assembly where you want the joint creation to take place.  (See image above for reference)

3) Next, click on the Script tab on the Ribbon, and then click on Launch.

4) Paste the script found below into the New Script window.  Click "Save as" in the Script section of the Ribbon, and save the script into a folder location of your choice.

5) Next, save the attached "JointCreatorIcon.png" file into the same folder you saved the script into from step (4) above.

6) Click "Run" from the Script section of the Ribbon, and the Joint Creator dialog will appear. 7) To populate the Tab Part field of the Joint Creator, click on one of the part names in the Design Explorer.

8) Next, click on the Base Part filed of the Joint Creator dialog, and then click on the 2nd part in the Design Explorer to populate its field.

9) Lastly, click the Create Joint button to generate the joint.

```# Joint Creator
# Version 1.00

from __future__ import division
from math import *

# gets locaton of edge in a part coordinate system
# returns a list of two points defining the edge
def GetPartEdge(Prt, SharedEdge):
Point1 = Prt.AssemblyPointtoPartPoint(SharedEdge)
Point2 = Prt.AssemblyPointtoPartPoint(SharedEdge)
return [Point1, Point2]

# compares two points [X1, Y1, Z1] and [X2, Y2, Z2]
# returns true if they are the same
def PointsAreEqual(P1, P2):
if (round(P1, 6) == round(P2, 6) and
round(P1, 6) == round(P2, 6) and
round(P1, 6) == round(P2, 6)):
return True
else:
return False

# gets part faces that use an edge
# returns a list of faces
def GetFacesFromEdge(Prt, SharedEdge):
Faces = []
PartEdge = GetPartEdge(Prt, SharedEdge)
for Fce in Prt.Faces:
for Edg in Fce.GetEdges():
EdgeVertices = Edg.GetVertices()
V1 = [EdgeVertices.X, EdgeVertices.Y, EdgeVertices.Z]
V2 = [EdgeVertices.X, EdgeVertices.Y, EdgeVertices.Z]
if ((PointsAreEqual(V1, PartEdge) and PointsAreEqual(V2, PartEdge)) or
(PointsAreEqual(V2, PartEdge) and PointsAreEqual(V1, PartEdge))):
Faces.append(Fce)
return Faces

# gets an edge that is shared between two parts
# returns list of edge vertices
def GetSharedEdge(Prt1, Prt2):
CornerVertices = []
for TabVert in Prt1.GetAssemblyVertices():
for BaseVert in Prt2.GetAssemblyVertices():
if PointsAreEqual(TabVert, BaseVert):
CornerVertices.append(TabVert)
return CornerVertices

# gets the length of an edge
# returns edge length
def GetEdgeLength(Vert1, Vert2):
a = abs(Vert2 - Vert1)
b = abs(Vert2 - Vert1)
c = abs(Vert2 - Vert1)
return sqrt(a * a + b * b + c * c)

# gets the largest face from a set of faces
def GetLargestFace(Faces):
if Faces.GetArea() > Faces.GetArea():
return Faces
elif Faces.GetArea() > Faces.GetArea():
return Faces
else:
print "Unable to determine face of part."
sys.exit()

# gets the smallest face from a set of faces
def GetSmallestFace(Faces):
if Faces.GetArea() < Faces.GetArea():
return Faces
elif Faces.GetArea() < Faces.GetArea():
return Faces
else:
print "Unable to determine face of part."
sys.exit()

# generates a range of real values from start to stop
# incremented by step
def frange(start, stop, step):
i = start
if start < stop:
while i < stop:
yield i
i += step
else:
while i > stop:
yield i
i += step

# gets the shortest edge of a face
# returns shortest edge
def GetShortestEdge(Fce):
Shortest = Fce.GetEdges()
for E in Fce.GetEdges():
if E.Length < Shortest.Length:
Shortest = E
return Shortest

# generates pin offsets
# NumPins = number of pins
# EdgeLength = length of edge for pins
# PinSense = True = slot at edge, False = pin at edge
# EdgeOffset = distance from ends of edges before pins
# Gap = distance between slot and pin
# returns: [ [Pin_1_Start, Pin_1_End], ..., [Pin_n_Start, Pin_n_End] ]
def GeneratePinOffsets(NumPins, EdgeLength, PinSense, EdgeOffset, Gap):
Offsets = []

# reduce length of edge by the edge offset at each end
# giving a length that we generate pins and slots over
PinEdgeLength = EdgeLength - (EdgeOffset * 2)

# get length of each pin
if PinSense == False:
PinLength = PinEdgeLength / (NumPins + (NumPins - 1))
PinState = True
else:
PinLength = PinEdgeLength / (NumPins + (NumPins + 1))
PinState = False

# generate start and end point of each pin
CurrentPin = 0
for Y in frange(EdgeOffset, EdgeLength - EdgeOffset, PinLength):
if PinState:
# if pins are never at the edges then always use gap on each
# side of pin
if PinSense == True:
Offsets.append([Y - Gap, Y + PinLength + Gap])
# pins could be at edges where we don't want the gap to be applied
else:
if CurrentPin == 0:
# first pin, no gap at start
Offsets.append([Y, Y + PinLength + Gap])
elif CurrentPin == NumPins - 1:
# last pin, no gap at end
Offsets.append([Y - Gap, Y + PinLength])
else:
# middle pin, gap at start and end
Offsets.append([Y - Gap, Y + PinLength + Gap])
CurrentPin += 1
PinState = not PinState

return Offsets

# generates slot offsets
# NumPins = number of pins
# EdgeLength = length of edge for slots
# PinSense = True = slot at edge, False = pin at edge
# EdgeOffset = distance from ends of edges before pins
# Gap = distance between slot and pin
# returns: [ [Slot_1_Start, Slot_1_End], ..., [Slot_n_Start, Slot_n_End] ]
def GenerateSlotOffsets(NumPins, EdgeLength, PinSense, EdgeOffset, Gap):
Offsets = []

# reduce length of edge by the edge offset at each end
# giving a length that we generate pins and slots over
PinEdgeLength = EdgeLength - (EdgeOffset * 2)

# get length of each pin
if PinSense == False:
PinLength = PinEdgeLength / (NumPins + (NumPins - 1))
PinState = False
else:
PinLength = PinEdgeLength / (NumPins + (NumPins + 1))
PinState = True

if PinSense == True:
NumSlots = NumPins + 1
else:
NumSlots = NumPins - 1

# add initial slot for edge offset if pins are on outside of slots
if EdgeOffset > 0 and PinSense == False:
Offsets.append([0, EdgeOffset + (Gap * 2.0)])

# generate start and end point of each slot
CurrentSlot = 0
for Y in frange(EdgeOffset, EdgeLength - EdgeOffset, PinLength):
if PinState:
# if slots are never at the edges then always use gap on each
# side of slot
if PinSense == False or (EdgeOffset > 0):
Offsets.append([Y - Gap, Y + PinLength + Gap])
# slots could be at edges where we don't want the gap to be applied
else:
if CurrentSlot == 0:
# first slot, no gap at start
Offsets.append([Y, Y + PinLength + Gap])
elif CurrentSlot == NumSlots - 1:
# last slot, no gap at end
Offsets.append([Y - Gap, Y + PinLength])
else:
# middle pin, gap at start and end
Offsets.append([Y - Gap, Y + PinLength + Gap])
CurrentSlot += 1
PinState = not PinState

# add final slot for edge offset if pins are on outside of slots
if EdgeOffset > 0 and PinSense == False:
Offsets.append([EdgeLength - EdgeOffset - (Gap * 2.0), EdgeLength])

if EdgeOffset > 0 and PinSense == True:
# extend first slot to cover edge offset
Offsets = 0
# extend last slot to cover edge offset
Offsets[len(Offsets) - 1] = EdgeLength

return Offsets

# generates the pins
# Prt = part to create pins on
# Fce = face on part to create pins
# PinOffsets = start and end values for pins
# Thickness = depth of pins
# SharedEdge = edge to generate pins along
def GeneratePins(Prt, Fce, PinOffsets, Thickness, SharedEdge):

TabEdge = GetPartEdge(Prt, SharedEdge)

TabProfile.StartFaceMapping(TabEdge, TabEdge)

for PinOffset in PinOffsets:

TabProfile.StopFaceMapping()

# cut out rectangles (pins)
Prt.AddExtrudeCut('Pins', TabProfile, 0, False, Part.EndCondition.ThroughAll, None, 0, Part.DirectionType.Normal, None, 0, False)

# generates the slots
# Prt = part to create slots on
# Fce = face on part to create slots
# SlotOffsets = start and end values for slots
# Thickness = depth of slots
# SharedEdge = edge to generate slots along
def GenerateSlots(Prt, Fce, SlotOffsets, Thickness, SharedEdge):

BaseEdge = GetPartEdge(Prt, SharedEdge)

BaseProfile.StartFaceMapping(BaseEdge, BaseEdge)

for SlotOffset in SlotOffsets:

BaseProfile.StopFaceMapping()

# cut out rectangles (slots)
Prt.AddExtrudeCut('Slots', BaseProfile, 0, False, Part.EndCondition.ThroughAll, None, 0, Part.DirectionType.Normal, None, 0, False)

# creates a joint based on user inputs
def CreateJoint(Values):
TabPart      = Values
BasePart     = Values
NumberofPins = Values
PinSense     = Values
EdgeOffset   = Values
Gap          = Values

print "Gathering information..."

# get edge shared by both parts
SharedEdge = GetSharedEdge(TabPart, BasePart)
# get the part faces for the shared edge
TabFaces = GetFacesFromEdge(TabPart, SharedEdge)
BaseFaces = GetFacesFromEdge(BasePart, SharedEdge)

# get the largest faces on each part that use the shared edge
TabFace = GetLargestFace(TabFaces)
BaseFace = GetLargestFace(BaseFaces)

# the smallest faces on each part that use the shared edge
TabEndFace = GetSmallestFace(TabFaces)
BaseEndFace = GetSmallestFace(BaseFaces)

# get length of shared edge
SharedEdgeLength = GetEdgeLength(SharedEdge, SharedEdge)

# get thickness of each part
TabThickness = GetShortestEdge(TabEndFace).Length
BaseThickness = GetShortestEdge(BaseEndFace).Length

print "Calculating..."

# generate pin and slot offsets
PinOffsets = GeneratePinOffsets(NumberofPins, SharedEdgeLength, PinSense, EdgeOffset, Gap / 2.0)
SlotOffsets = GenerateSlotOffsets(NumberofPins, SharedEdgeLength, PinSense, EdgeOffset, Gap / 2.0)

print "Generating..."

# generate pins and slots
GeneratePins(TabPart, TabFace, PinOffsets, BaseThickness, SharedEdge)
GenerateSlots(BasePart, BaseFace, SlotOffsets, TabThickness, SharedEdge)

print "Finished"

#################################################################################################

# check minimum requirements
if AlibreScriptVersion < 1110:

ScriptName = 'Joint Creator'

Win = Windows()

# define options to show in dialog window
Options = []
Options.append([None, WindowsInputTypes.Image, 'JointCreatorIcon.png', 200])
Options.append(['Tab Part', WindowsInputTypes.Part, None])
Options.append(['Base Part', WindowsInputTypes.Part, None])
Options.append(['Number of Pins', WindowsInputTypes.Integer, 5])
Options.append(['Pins on Inside', WindowsInputTypes.Boolean, False])
Options.append(['Offset From Ends', WindowsInputTypes.Real, 0.0])
Options.append(['Gap Between Pins and Slots', WindowsInputTypes.Real, 0.0])

# show utility window
Win.UtilityDialog(ScriptName, 'Create Joint', CreateJoint, None, Options, 200)```

Did you find it helpful? Yes No

Send feedback 