execuc / LCInterlocking

FreeCAD module to create laser cut interlocking parts.
GNU Lesser General Public License v2.1
143 stars 32 forks source link

Interlocking: AttributeError: 'NoneType' object has no attribute 'Length' #53

Open sdesalve opened 3 years ago

sdesalve commented 3 years ago

Hi, I wasn't able to make interlocking pieces between a boolean and a solid from a sketch. I've tried also to make simple copies of objects. Is my object (LABEL: "Cut") too complex for making interlocking?

I'm getting this error:

16:37:03  Traceback (most recent call last):
16:37:03    File "C:\Users\x\AppData\Roaming\FreeCAD\Mod\LCInterlocking\panel\treepanel.py", line 255, in add_tabs
16:37:03      item = self.tabsList.append(face, self.tab_type_box.currentText())
16:37:03    File "C:\Users\x\AppData\Roaming\FreeCAD\Mod\LCInterlocking\panel\tab.py", line 165, in append
16:37:03      tab_properties = TabProperties(freecad_face=face['face'],
16:37:03    File "C:\Users\x\AppData\Roaming\FreeCAD\Mod\LCInterlocking\lasercut\tabproperties.py", line 71, in __init__
16:37:03      self.thickness = thickness.Length
16:37:03  AttributeError: 'NoneType' object has no attribute 'Length'

I've attached my file: v4.zip

OS: Windows 10 (10.0) Word size of FreeCAD: 64-bit Version: 0.20.25429 (Git) Build type: Release Branch: master Hash: acce57a25d82b0408fa07b9452ed31c8a06c7a1b Python version: 3.8.10 Qt version: 5.12.9 Coin version: 4.0.0 OCC version: 7.5.2 Locale: Italian/Italy (it_IT)

Thanks SDeSalve

randomdude commented 2 years ago

I had the same problem. I think it's due to a face having more than four points (even a rectangular face may have more than four points, as some may be redundant or used for connecting shapes).

I was able to bodge it in to working by replacing the get_local_axis function in helper.py:


def getExtends(edge):
    extends_X = (edge.Vertexes[0].X != edge.Vertexes[1].X)
    extends_Y = (edge.Vertexes[0].Y != edge.Vertexes[1].Y)
    extends_Z = (edge.Vertexes[0].Z != edge.Vertexes[1].Z)

    return extends_X, extends_Y, extends_Z

def get_local_axis(face):
    list_edges = Part.__sortEdges__(face.Edges)

    coalescedEdges = []
    previousEdge = None
    for edge in list_edges:
        extends_X, extends_Y, extends_Z = getExtends(edge)

        if previousEdge is not None:
            # If we extend in only one direction, and that is the same direction as the previous edge,
            # then we can merge the two edges together.
            dirsExtended = 0
            if extends_X:
                dirsExtended = dirsExtended + 1
            if extends_Y:
                dirsExtended = dirsExtended + 1
            if extends_Z:
                dirsExtended = dirsExtended + 1

            if dirsExtended == 1 and extends_X == prev_extends_X and extends_Y == prev_extends_Y and extends_Z == prev_extends_Z:
                if extends_X:
                    coalescedEdges[-1].Vertexes[1] = Part.Vertex(  edge.Vertexes[1].X, coalescedEdges[-1].Vertexes[1].Y, coalescedEdges[-1].Vertexes[1].Z)

                if extends_Y:
                    ls = Part.LineSegment( coalescedEdges[-1].Vertexes[0].Point, FreeCAD.Vector(coalescedEdges[-1].Vertexes[1].X, edge.Vertexes[1].Y, coalescedEdges[-1].Vertexes[1].Z) )
                    coalescedEdges[-1] = Part.Edge(ls)

                if extends_Z:
                    coalescedEdges[-1].Vertexes[1] = Part.Vertex( coalescedEdges[-1].Vertexes[1].X, coalescedEdges[-1].Vertexes[1].Y, edge.Vertexes[1].Z)
            else:
                coalescedEdges.append(edge)
        else:
            coalescedEdges.append(edge)

        prev_extends_X = extends_X
        prev_extends_Y = extends_Y
        prev_extends_Z = extends_Z
        previousEdge = edge

    # And check in case the last edge is an extension of the first.
    extends_X, extends_Y, extends_Z = getExtends(coalescedEdges[-1])
    prev_extends_X, prev_extends_Y, prev_extends_Z = getExtends(coalescedEdges[0])

    dirsExtended = 0
    if extends_X:
        dirsExtended = dirsExtended + 1

    if extends_Y:
        dirsExtended = dirsExtended + 1

    if extends_Z:
        dirsExtended = dirsExtended + 1

    if dirsExtended == 1 and extends_X == prev_extends_X and extends_Y == prev_extends_Y and extends_Z == prev_extends_Z:
        if extends_X:
            coalescedEdges[-1].Vertexes[1] = Part.Vertex( coalescedEdges[0].Vertexes[1].X, coalescedEdges[-1].Vertexes[1].Y, coalescedEdges[-1].Vertexes[1].Z)

        if extends_Y:
            ls = Part.LineSegment( coalescedEdges[-1].Vertexes[0].Point, FreeCAD.Vector(coalescedEdges[-1].Vertexes[1].X, edge.Vertexes[1].Y, coalescedEdges[-1].Vertexes[1].Z) )
            coalescedEdges[-1] = Part.Edge(ls)

        if extends_Z:
            coalescedEdges[-1].Vertexes[1] = Part.Vertex( coalescedEdges[-1].Vertexes[1].X, coalescedEdges[-1].Vertexes[1].Y, coalescedEdges[0].Vertexes[1].Z)

        coalescedEdges.remove(coalescedEdges[0])

    list_edges = coalescedEdges

    #get_local_axis(elt)

    list_points = sort_quad_vertex(list_edges, False)
    if list_points is None:
        list_points = sort_quad_vertex(list_edges, True)
    if list_points is None:
        raise ValueError("Error sorting vertex")

    normal_face = face.normalAt(0, 0)
    y_local = None
    z_local = None
    #x_local = normal_face.negative()
    x_local = normal_face.normalize()
    z_local_not_normalized = None
    y_local_not_normalized = None
    for x in range(0, len(list_edges)):
        vector1 = list_points[(x + 1) % len(list_edges)] - list_points[x]
        vector2 = list_points[(x - 1) % len(list_edges)] - list_points[x]
        y_local = None
        z_local = None
        if vector1.Length >= vector2.Length:
            z_local_not_normalized = vector2 * 1
            y_local_not_normalized = vector1 * 1
            y_local = vector1.normalize()
            z_local = vector2.normalize()
        else:
            z_local_not_normalized = vector1 * 1
            y_local_not_normalized = vector2 * 1
            y_local = vector2.normalize()
            z_local = vector1.normalize()

        computed_x_local = y_local.cross(z_local)

        if compare_freecad_vector(computed_x_local, x_local):
            return x_local, y_local_not_normalized, z_local_not_normalized

    return None, None, None

Please note that I haven't got a clue about geometry, and so I don't know if this will help at all! It might make things worse! Hopefully someone with deeper knowlege can help out later, but in the meantime, I hope this helps. It's horribly written, I know. But it works [for me.]