Add a Joint Based on Proximity of Two Named Selections

Goal: Given a named selection of N faces and another of N*2 faces, add a joint between each face in the first named selection and the nearest two faces in the second named selection.

Code:

import math

#distance formula where c1 and c2 are each arrays of 3 real numbers
def dist(c1, c2):
    x = c1[0]-c2[0]
    x = x*x
    y = c1[1]-c2[1]
    y = y*y
    z = c1[2]-c2[2]
    z = z*z
    return math.sqrt(x+y+z)

jh1 = DataModel.GetObjectsByName("jh1")[0]       #named selection object of faces to become the single joint reference scope
jh2 = DataModel.GetObjectsByName("jh2")[0]       #named selection object of faces from which the two closest will become the mobile scope
group = DataModel.GetObjectsByName("Connection Group")[0]       #connection group to hold all of the joints that are added

geo = DataModel.GeoData
face_ids1 = jh1.Location.Ids       #face ids in jh1
face_ids2 = jh2.Location.Ids       #face ids in jh2

#get the centroids of all faces in face_ids2
face_centroids2 = [geo.GeoEntityById(face_id2).Centroid for face_id2 in face_ids2]

def get_min_indeces(face_centroid1):
    #array to hold the index and distance to face1_center for two closest faces in face_centroids2
    min_indeces = [None, None]

    for index in range(len(face_centroids2)):
        face_centroid2 = face_centroids2[index]
        distance = dist(face_centroid1, face_centroid2)

        #initilize with the first two iterations of this loop
        if index == 0:
            min_indeces[0] = (index, distance)
            continue
        if index == 1:
            min_indeces[1] = (index, distance)
            continue

        #get the index of the item with the larger distance
        if min_indeces[0][1] < min_indeces[1][1]:
            larger_dist_index = 1
        else:
            larger_dist_index = 0

        #replace that item with the current face if the distance is smaller
        if distance < min_indeces[larger_dist_index][1]:
            min_indeces[larger_dist_index] = (index, distance)
    return min_indeces

#use a transaction to speed up adding joints to the tree in a loop
with Transaction():
    for face_id1 in face_ids1:
        face1 = geo.GeoEntityById(face_id1)
        face_centroid1 = face1.Centroid       #get the centroid of each face in face_ids1
        min_indeces = get_min_indeces(face_centroid1)

        #get the face ids using the indices computed above
        face_ids = [face_ids2[min_indeces[0][0]], face_ids2[min_indeces[1][0]]]

        #add a joint and assign its geometry selection
        joint = group.AddJoint()

        reference_selection = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities)
        reference_selection.Ids = [face_id1]

        mobile_selection = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities)
        mobile_selection.Ids = face_ids

        joint.ReferenceLocation = reference_selection
        joint.MobileLocation = mobile_selection