@Override
  public PartLink filterPartLink(List<PartLink> path) {

    // No ambiguities here, must return 1 value
    // Check if optional or substitute, nominal link else

    PartLink nominalLink = path.get(path.size() - 1);

    if (nominalLink.isOptional() && optionalUsageLinks.contains(Tools.getPathAsString(path))) {
      retainedOptionalUsageLinks.add(Tools.getPathAsString(path));
      return null;
    }

    for (PartSubstituteLink substituteLink : nominalLink.getSubstitutes()) {

      List<PartLink> substitutePath = new ArrayList<>(path);
      substitutePath.set(substitutePath.size() - 1, substituteLink);

      if (substituteLinks.contains(Tools.getPathAsString(substitutePath))) {
        retainedSubstituteLinks.add(Tools.getPathAsString(substitutePath));
        return substituteLink;
      }
    }

    return nominalLink;
  }
  private static void writeLeaf(
      List<PartLink> currentPath,
      List<Integer> copyInstanceIds,
      PartIteration partI,
      Matrix4d combinedMatrix,
      JsonGenerator jg) {
    String partIterationId = partI.toString();
    List<InstanceAttributeDTO> attributes = new ArrayList<>();
    for (InstanceAttribute attr : partI.getInstanceAttributes()) {
      attributes.add(mapper.map(attr, InstanceAttributeDTO.class));
    }

    jg.writeStartObject();
    jg.write("id", Tools.getPathInstanceAsString(currentPath, copyInstanceIds));
    jg.write("partIterationId", partIterationId);
    jg.write("path", Tools.getPathAsString(currentPath));

    writeMatrix(combinedMatrix, jg);
    writeGeometries(partI.getSortedGeometries(), jg);
    writeAttributes(attributes, jg);

    jg.writeEnd();
    jg.flush();
  }