Thursday, 17 November 2016

FreeCAD: Bolts, nuts, washers..., one helping tool!


If you decide to add bolts, nuts, washers, etc, to your assembly, and it is somewhat complicated, you may end spending a lot of time placing this tiny parts all around the 3D space. At least, that has been happening to me from time to time. In this post I introduce you the tool I coded to deal with this situation:

def placeBolts():
  sel_obj = FreeCAD.Gui.Selection.getSelectionEx()[0].Object
  sel_edge = FreeCAD.Gui.Selection.getSelectionEx()[0].SubObjects[0]

  sel_edge_number = -1
  for edge in sel_obj.Shape.Edges:
    sel_edge_number += 1
    if (edge.CenterOfMass - sel_edge.CenterOfMass).Length < 0.001:
  parent_folder = None
  def findParentFolder():
    # find the group that sel_obj pertains to
    for obj in FreeCAD.ActiveDocument.Objects:
      if obj.TypeId == 'App::DocumentObjectGroup':
        for sub_obj in obj.Group:
          if sub_obj.Name == sel_obj.Name:
            return obj
    return None

  parent_folder = findParentFolder()
  if len( FreeCAD.Gui.Selection.getSelectionEx())  == 2:
    target_edges = FreeCAD.Gui.Selection.getSelectionEx()[1].SubObjects

  elif len( FreeCAD.Gui.Selection.getSelectionEx())  > 2:
    target_edges = []
    for i in xrange( len( FreeCAD.Gui.Selection.getSelectionEx() ) - 1 ):
      for sub_object in FreeCAD.Gui.Selection.getSelectionEx()[i+1].SubObjects:
        target_edges.append( sub_object )
  for edge in target_edges:
    # create new object in document
    new_obj = FreeCAD.ActiveDocument.addObject( 'Part::Feature', sel_obj.Name + '_copy' )
    # assign a shape to the created object
    new_obj.Shape = sel_obj.Shape.copy()
    # assign the view object to copy colors
    new_obj.ViewObject.ShapeColor = sel_obj.ViewObject.ShapeColor
    new_obj.ViewObject.LineColor = sel_obj.ViewObject.LineColor
    new_obj.ViewObject.Transparency = sel_obj.ViewObject.Transparency
    # move this object to a folder if selected object was in a folder
    if parent_folder:
      parent_folder.addObject( new_obj )
    # place the new object at the desired target
    VA = new_obj.Shape.Edges[sel_edge_number].Curve.Center
    VB = edge.Curve.Center
    DV = VB - VA
    new_obj.Placement.Base.x += DV.x
    new_obj.Placement.Base.y += DV.y
    new_obj.Placement.Base.z += DV.z

This function is called "placeBolts" and has no arguments. To use it, open the python terminal inside FreeCAD and copy-paste the code above, then continue reading.

How to select the objects to place:

In the picture there is a rectangular pad with 5 holes on which I want to place the washer (also present in the drawing):

First select the circular arc of the washer that is going to be in contact with the hole in the pad, like this (notice the thin circular edge selected at the bottom of the inner cylinder of the washer in the picture below):

Second select all the edges of the rectangular part that will be in contact with the washer.

Third, copy paste this line at they python terminal:


And its done!

The washers are placed at the selected positions and if the original washer which served as a model was inside a folder, the created copies will be appended within the same folder (this is gold when you are in a big assembly)


This tool works for circular edges only, but the vast majority of parts that could benefit from it have them (bolts, nuts, washers, threaded rods... ), so I do not consider it a big drawback.

I may include this as an auxiliary assembly tool in the exploded assembly workbench.

Have fun.