示例#1
0
def _cell_update_halfface(volmesh, hfkey, xyz, normal=None):
    """Return new coordinates for the halfface.
    """

    new_cell_xyz = {}

    ckey = volmesh.halfface_cell(hfkey)
    cell_vkeys = volmesh.cell_vertices(ckey)
    hf_vkeys = volmesh.halfface_vertices(hfkey)
    if not normal:
        normal = volmesh.halfface_normal(hfkey)
    plane = (xyz, normal)

    edges = {key: [] for key in hf_vkeys}
    for u in hf_vkeys:
        nbrs = volmesh.vertex_neighbors(u)
        for v in nbrs:
            if v not in hf_vkeys and v in cell_vkeys:
                edges[u].append(v)

    for u in hf_vkeys:
        v = edges[u][0]
        u_xyz = volmesh.vertex_coordinates(u)
        v_xyz = volmesh.vertex_coordinates(v)
        line = (u_xyz, v_xyz)
        it = intersection_line_plane(line, plane)
        new_cell_xyz[u] = it

    return new_cell_xyz
示例#2
0
def intersect_residual(boundary, frame):
    intersections = []
    for key in boundary:
        a = cablenet.vertex_coordinates(key)
        r = cablenet.residual(key)
        b = add_vectors(a, r)
        pt = intersection_line_plane((a, b), (frame.point, frame.zaxis))
        intersections.append(pt)

    return intersections
示例#3
0
def dropped_perpendicular_points(line_point_1_1, line_point_1_2, line_point_2_1, line_point_2_2):
    """compute the projected tangent point on axis defined by [L1_pt1, L1_pt2] and [L2_pt1, L2_pt2]

    See Fig. 3.7 in SP's dissertaion (below). We are computing the point pair (P1, P_{C1}) here, given the axis endpoints of bar b_{e1} and b_{n1}

    .. image:: ../images/perpendicular_bar_tangent_to_two_existing_bars.png
        :scale: 80 %
        :alt: perpendicular_bar_tangent_to_two_existing_bars
        :align: center

    Parameters
    ----------
    line_point_1_1 : [type]
        [description]
    line_point_1_2 : [type]
        [description]
    line_point_2_1 : [type]
        [description]
    line_point_2_2 : [type]
        [description]

    Returns
    -------
    list of two points
       representing the contact line segment between the two axes
    """
    line_unity_vector_1 = normalize_vector(vector_from_points(line_point_1_1, line_point_1_2))
    line_unity_vector_2 = normalize_vector(vector_from_points(line_point_2_1, line_point_2_2))
    d_vector = cross_vectors(line_unity_vector_1, line_unity_vector_2)

    normal_1 = cross_vectors(line_unity_vector_1, d_vector)
    normal_2 = cross_vectors(line_unity_vector_2, d_vector)
    plane_1 = (line_point_1_1, normal_1)
    plane_2 = (line_point_2_1, normal_2)
    line_1_dp_point = intersection_line_plane((line_point_1_1, line_point_1_2), plane_2)
    line_2_dp_point = intersection_line_plane((line_point_2_1, line_point_2_2), plane_1)

    return [line_1_dp_point, line_2_dp_point]
示例#4
0
def reflect_line_plane(line, plane, tol=1e-6):
    """Bounce a line of a reflection plane.

    Parameters
    ----------
    line : tuple
        Two points defining the line.
    plane : tuple
        Base point and normal vector of the plane.
    tol : float, optional
        A tolerance for membership verification.
        Default is ``1e-6``.

    Returns
    -------
    tuple
        The reflected line defined by the intersection point of the line and plane
        and the mirrored start point of the line with respect to a line perpendicular
        to the plane through the intersection.

    Notes
    -----
    The direction of the line and plane are important.
    The line is only reflected if it points towards the front of the plane.
    This is true if the dot product of the direction vector of the line and the
    normal vector of the plane is smaller than zero.

    Examples
    --------
    >>> plane = [0, 0, 0], [0, 1, 0]
    >>> line = [-1, 1, 0], [-0.5, 0.5, 0]
    >>> reflect_line_plane(line, plane)
    ([0.0, 0.0, 0.0], [1.0, 1.0, 0.0])

    """
    x = intersection_line_plane(line, plane, tol=tol)
    if not x:
        return

    a, b = line
    o, n = plane
    ab = subtract_vectors(b, a)

    if dot_vectors(ab, n) > 0:
        # the line does not point towards the front of the plane
        return

    mirror = x, add_vectors(x, n)
    return x, mirror_point_line(a, mirror)
示例#5
0
def cell_relocate_face(cell, fkey, xyz, normal):
    """Relocate the face of a mesh.

    Parameters
    ----------
    cell : Mesh
        Cell as a mesh object.
    fkey : hashable
        Identifier of the face.
    xyz : tuple
        xyz coordinates of the new target plane.
    normal : tuple
        Target normal vector.

    Returns
    -------
    cell : Mesh
        Updated cell.
    """

    cell_split_indet_face_vertices(cell, fkey)

    vkeys = cell.face_vertices(fkey)

    # new target plane for the face
    plane = (xyz, normal)

    # neighboring edges
    edges = {}
    for u in vkeys:
        for v in cell.vertex_neighbors(u):
            if v not in vkeys:
                edges[u] = v

    for u in edges:
        line = cell.edge_coordinates(u, edges[u])
        it = intersection_line_plane(line, plane)
        cell.vertex_update_xyz(u, it, constrained=False)

    return cell
示例#6
0
    def OnDynamicDraw(sender, e):

        cp = e.CurrentPoint
        plane = (cp, normal)
        line = (center, add_vectors(center, normal))
        it = intersection_line_plane(line, plane)

        translation = subtract_vectors(it, center)
        dot = dot_vectors(normal, translation)
        dot = dot / abs(dot)

        dist = distance_point_point(center, it) * dot

        for hfkey in hfkeys:
            hf_center = volmesh.halfface_center(hfkey)
            hf_normal = volmesh.halfface_oriented_normal(hfkey)
            ep = add_vectors(hf_center, scale_vector(hf_normal, dist))
            e.Display.DrawDottedLine(Point3d(*hf_center), Point3d(*ep),
                                     feedback_color)
            e.Display.DrawPoint(Point3d(*ep), 0, 4, black)
            for vkey in volmesh.halfface_vertices(hfkey):
                sp = volmesh.vertex_coordinates(vkey)
                e.Display.DrawLine(Point3d(*sp), Point3d(*ep), black, 2)
示例#7
0
    hits = igl.intersection_ray_mesh(ray, mesh)
    if hits:
        i1, r1 = ray_mesh_intersect_reflect(ray, mesh, hits[0], index_face)
        intersections.append(i1)
        vector = r1 - i1
        vector.unitize()
        ray = i1, vector
        hits = igl.intersection_ray_mesh(ray, mesh)
        if hits:
            if len(hits) > 1:
                hit = hits[1]
            else:
                hit = hits[0]
            i2, _ = ray_mesh_intersect_reflect(ray, mesh, hit, index_face)
            if (i2 - i1).length < 0.01:
                x = intersection_line_plane((i1, r1), ground)
                r1 = Point(*x)
                reflections.append((i1, r1))
            else:
                reflections.append((i1, i2))
        else:
            x = intersection_line_plane((i1, r1), ground)
            r1 = Point(*x)
            reflections.append((i1, r1))

# ==============================================================================
# Visualisation
# ==============================================================================

viewer = ObjectViewer()
def RunCommand(is_interactive):

    #load Derivation and model
    derivation = Derivation.from_json(
        rhino_UI_utilities.get_json_file_location())
    model = derivation.get_next_step()

    #select beams
    selection_reference = []
    selection_reference.append(
        rs.GetObject(message="select start Beam", filter=32, preselect=True))
    selection_reference.extend(
        rs.GetObjects(message="select Beams to connect",
                      filter=32,
                      preselect=True))

    #load helpers
    helper = UI_helpers()

    #name search
    selected_beams = helper.extract_BeambyName(model, selection_reference)

    #check for parallel planes, uses the function above
    start_beam = selected_beams[0]
    beams_to_connect = selected_beams[1:]
    parallel_check = check_for_parallel_vectors(start_beam, beams_to_connect)
    if parallel_check != True:
        raise IndexError('beams are not parallel')
    else:
        print("beams are parallel")

    #check for coplanarity, uses the function above
    coplanar_planes = {}
    face_ids_coplanar_planes = {}
    for i in range(1, 5):
        start_beam_plane = start_beam.face_plane(i).copy()
        start_beam_origin = start_beam_plane.point
        a = get_coplanar_planes(start_beam_plane, start_beam_origin,
                                beams_to_connect)
        if a != False:
            coplanar_planes['' + str(i)] = a[0]
            face_ids_coplanar_planes['' + str(i)] = a[1]
        else:
            pass
    print("face_dictionary here", face_ids_coplanar_planes)
    if len(coplanar_planes.keys()) == 2:
        print("'success", coplanar_planes)
    else:
        raise IndexError('beams are not coplanar')

    #user inputs
    face_id = rs.GetInteger(("possible face connections " + "face_id " +
                             coplanar_planes.keys()[0] + " or face_id " +
                             coplanar_planes.keys()[1]), None, None, None)
    start_point = (helper.Get_SelectPointOnMeshEdge("Select mesh edge",
                                                    "Pick point on edge"))
    ext_start = rs.GetReal("extension length start", 200, None, None)
    ext_end = rs.GetReal("extension length end", 200, None, None)

    #list of coplanar planes extracted from coplanar_planes dict using face_id as key
    coplanar_planes_along_selected_face = []
    coplanar_planes_along_selected_face.append(
        start_beam.face_plane(face_id).copy())
    for key, value in coplanar_planes.items():
        if key == "" + str(face_id):
            coplanar_planes_along_selected_face.extend(value)

    #list of face_ids of coplanar planes
    coplanar_face_ids = []
    coplanar_face_ids.append(face_id)
    for key, value in face_ids_coplanar_planes.items():
        if key == "" + str(face_id):
            coplanar_face_ids.extend(value)

    #intersection points by passing a line from the origin of start beam to the adjacent planes of the coplanar planes of all beams
    points_to_compare = []
    for i in range(len(selected_beams)):
        beam = selected_beams[i]
        start_beam_selected_face_frame = selected_beams[0].face_frame(face_id)
        line_pt_a = start_beam_selected_face_frame.point
        normal = start_beam_selected_face_frame.normal
        line_pt_b = add_vectors(line_pt_a, scale_vector(normal, 0.3))
        line_to_intersect = Line(line_pt_a, line_pt_b)

        face_index = coplanar_face_ids[i]
        adjacent_planes = beam.neighbour_face_plane(face_index)
        for p in adjacent_planes:
            intersection_point = intersection_line_plane(line_to_intersect, p)
            points_to_compare.append(intersection_point)

    viz_pts = []
    #project distance from  points_to_compare to the plane of the start Beam
    distances = []
    start_beam_face_frame = start_beam.face_frame(face_id).copy()
    start_beam_Plane_perpendicular_to_face_id_Plane = Plane(
        start_beam_face_frame.point, start_beam_face_frame.normal)
    viz_pts.append(start_beam_Plane_perpendicular_to_face_id_Plane.point)
    for point in points_to_compare:
        viz_pts.append(point)
        vector = subtract_vectors(
            point, start_beam_Plane_perpendicular_to_face_id_Plane.point)
        distances.append(
            dot_vectors(
                vector,
                start_beam_Plane_perpendicular_to_face_id_Plane.normal))

    #search to find max point
    maximum_distance = max(distances)
    minimum_distance = min(distances)
    beam_length = (maximum_distance - minimum_distance) + ext_start + ext_end
    ext_len = maximum_distance + ext_start

    #project selected point to perpendicular planes of the beams to connect
    if coplanar_planes.keys()[0] == "1" or coplanar_planes.keys()[0] == "3":
        start_beam_perpendicular_plane = start_beam.face_plane(5).copy()

    elif coplanar_planes.keys()[0] == "2" or coplanar_planes.keys()[0] == "4":
        start_beam_perpendicular_plane = start_beam.face_plane(6).copy()

    tol = 1.0e-5
    # tol = 5.0
    perpendicular_plane = []
    for beam in beams_to_connect:
        for i in range(5, 7):
            beam_plane = beam.face_plane(i).copy()
            print("beam_plane", beam_plane)
            angle_check = start_beam_perpendicular_plane.normal.angle(
                beam_plane.normal)
            print("angle", angle_check)
            if (abs(angle_check) - 0) < tol or (abs(angle_check) - 180) < tol:
                perpendicular_plane.append(beam_plane)

    print(perpendicular_plane)
    print(len(perpendicular_plane))
    #project points
    projected_point_list = []
    new_start_point = project_points_plane([start_point],
                                           start_beam_perpendicular_plane)
    projected_point_list.extend(new_start_point)
    for plane in perpendicular_plane:
        new_point = project_points_plane(new_start_point, plane)
        projected_point_list.extend(new_point)

    #list of distance to move joints on match beam
    model.rule_Connect_90lap(selected_beams, projected_point_list,
                             coplanar_face_ids, beam_length, ext_len,
                             create_id())
    print(len(projected_point_list))
    print(projected_point_list)

    #Save Derivation (Model is also saved)
    derivation.to_json(rhino_UI_utilities.get_json_file_location(),
                       pretty=True)

    # Visualization
    viz_point = []
    for pt in projected_point_list:
        a = (pt[0], pt[1], pt[2])
        viz_point.append({'pos': a, 'color': (0, 255, 0)})

    artist = MeshArtist(None, layer='BEAM::Beams_out')
    artist.clear_layer()
    artist.draw_points(viz_point)
    for beam in model.beams:
        artist = MeshArtist(
            beam.mesh, layer='BEAM::Beams_out'
        )  #.mesh is not ideal fix in beam and assemble class
        artist.draw_faces(join_faces=True)
示例#9
0
    bottom = ...

    # the vertices of the top face are the intersection points of the face normal
    # placed at each (offset) bottom vertex and a plane perpendicular to the 
    # face normal placed at a distance THICKNESS along the face normal from the
    # face centroid.

    # define the plane
    origin = ...
    normal = ...
    plane = add_vectors(origin, ...), normal

    top = []
    for a in bottom:
        b = ...
        ... = intersection_line_plane(...)
        top.append(...)

    top[:] = ...

    vertices = ... + ...
    faces = [[0, 3, 2, 1], ..., [3, 0, 4, 7], [2, 3, 7, 6], [1, 2, 6, 5], [0, 1, 5, 4]]

    block = Mesh.from_...(...)

    blocks.append(block)

# ==============================================================================
# Visualize the block with a mesh artist in the specified layer. Use
# `draw_faces` (with `join_faces=True`) instead of `draw_mesh` to get a flat
# shaded result. Also draw the vertex labels tovisualize the cycle directions.
def point_on_plane(point, frame, direction=None):
    if direction is None:
        direction = frame.normal
    line = line_sdl(point, direction, 1.0)
    return intersection_line_plane((line.start, line.end),
                                   (frame.point, frame.normal))
示例#11
0
right_vertices = right_vertices[i:] + right_vertices[:i]
right_points = block.vertices_attributes('xyz', keys=right_vertices)

# ==============================================================================
# Movement paths
# ==============================================================================

left_plane = Plane([0, 0, 0], [-1, 0, 0])
right_plane = Plane([WIRE, 0, 0], [+1, 0, 0])

left_intersections = [left_plane.point]
right_intersections = [right_plane.point]

for line in zip(left_points, right_points):
    left_x = intersection_line_plane(line, left_plane)
    right_x = intersection_line_plane(line, right_plane)

    left_intersections.append(left_x)
    right_intersections.append(right_x)

left_intersections.append(left_intersections[1])
right_intersections.append(right_intersections[1])

left_intersections.append(left_intersections[0])
right_intersections.append(right_intersections[0])

# polylines

left_poly = Polyline(left_intersections)
right_poly = Polyline(right_intersections)
示例#12
0
def rhino_volmesh_halfface_pinch(volmesh):
    hfkeys = _select_boundary_halffaces(volmesh)

    key = hfkeys[0]

    center = volmesh.halfface_center(key)
    normal = volmesh.halfface_oriented_normal(key)
    line = (center, add_vectors(center, normal))

    # --------------------------------------------------------------------------
    #  dynamic draw
    # --------------------------------------------------------------------------
    rs.EnableRedraw(True)

    def OnDynamicDraw(sender, e):

        cp = e.CurrentPoint
        plane = (cp, normal)
        line = (center, add_vectors(center, normal))
        it = intersection_line_plane(line, plane)

        translation = subtract_vectors(it, center)
        dot = dot_vectors(normal, translation)
        dot = dot / abs(dot)

        dist = distance_point_point(center, it) * dot

        for hfkey in hfkeys:
            hf_center = volmesh.halfface_center(hfkey)
            hf_normal = volmesh.halfface_oriented_normal(hfkey)
            ep = add_vectors(hf_center, scale_vector(hf_normal, dist))
            e.Display.DrawDottedLine(Point3d(*hf_center), Point3d(*ep),
                                     feedback_color)
            e.Display.DrawPoint(Point3d(*ep), 0, 4, black)
            for vkey in volmesh.halfface_vertices(hfkey):
                sp = volmesh.vertex_coordinates(vkey)
                e.Display.DrawLine(Point3d(*sp), Point3d(*ep), black, 2)

    # --------------------------------------------------------------------------
    #  input point
    # --------------------------------------------------------------------------
    ip = Point3d(*center)
    axis = Rhino.Geometry.Line(ip, ip + Vector3d(*normal))
    gp = get_target_point(axis, OnDynamicDraw)

    plane = (gp, normal)
    it = intersection_line_plane(line, plane)

    translation = subtract_vectors(it, center)
    dot = dot_vectors(normal, translation)
    dot = dot / abs(dot)

    rise = distance_point_point(center, it) * dot

    for hfkey in hfkeys:
        hf_center = volmesh.halfface_center(hfkey)
        hf_normal = volmesh.halfface_oriented_normal(hfkey)
        ep = add_vectors(hf_center, scale_vector(hf_normal, rise))

        volmesh_halfface_pinch(volmesh, hfkey, ep)

    volmesh.draw()

    return volmesh
示例#13
0
shell = Shell.from_json(FILE_I)

keys = [268, 258, 115, 106, 114, 269, 281, 145]
origin = [0, 2.5, 0]
normal = [0, 1.0, 0]
plane = (origin, normal)

points = []
rhinopoints = []
for key in keys:
    a = shell.vertex_coordinates(key)
    r = shell.get_vertex_attributes(key, ['rx', 'ry', 'rz'])
    b = add_vectors(a, r)
    line = a, b
    x = intersection_line_plane(line, plane)
    points.append(x)

    rhinopoints.append({
        'pos'   : x,
        'color' : (0, 0, 255),
        'name'  : "{}.{}.anchor".format(shell.name, key)
    })

box = bounding_box(points)

lines = []
for i, j in [(0, 1), (1, 5), (5, 4), (4, 0)]:
    a = box[i]
    b = box[j]
    d = distance_point_point(a, b)
示例#14
0
    def OnDynamicDraw(sender, e):

        cp = e.CurrentPoint
        plane = (cp, f_normal)
        new_pt_list = []

        for u in f_vkeys:
            v = edges[u]
            u_xyz = cell.vertex_coordinates(u)
            v_xyz = cell.vertex_coordinates(v)
            line = (u_xyz, v_xyz)
            it = intersection_line_plane(line, plane)
            xyz_dict[u] = it
            new_pt_list.append(it)

            e.Display.DrawDottedLine(Point3d(*u_xyz), Point3d(*it), black)

        for vkey in cell.vertex:
            xyz = cell.vertex_coordinates(vkey)
            e.Display.DrawPoint(Point3d(*xyz), 0, 5, black)

        # old normal and area --------------------------------------------------
        e.Display.DrawDot(Point3d(*f_center), str(round(f_area, 3)), gray,
                          white)

        # draw original face ---------------------------------------------------
        for i in range(-1, len(f_vkeys) - 1):
            vkey1 = f_vkeys[i]
            vkey2 = f_vkeys[i + 1]
            sp = Point3d(*cell.vertex_coordinates(vkey1))
            np = Point3d(*cell.vertex_coordinates(vkey2))

            e.Display.DrawDottedLine(sp, np, black)

        # get current face info ------------------------------------------------
        areas = {}
        normals = {}
        for fkey in cell.faces():
            face_coordinates = [
                xyz_dict[vkey] for vkey in cell.face_vertices(fkey)
            ]
            areas[fkey] = polygon_area_oriented(face_coordinates)
            normals[fkey] = polygon_normal_oriented(face_coordinates)

        # draw new face areas / vectors ----------------------------------------
        for fkey in cell.faces():
            area = areas[fkey]
            normal = normals[fkey]
            value = area / max(areas.values())
            color = i_to_rgb(value)
            color = FromArgb(*color)

            # draw vectors -----------------------------------------------------
            scale = 0.25
            center = datastructure_centroid(cell)
            sp = Point3d(*center)
            vector = scale_vector(normal, area * scale)
            ep = Point3d(*add_vectors(center, vector))

            e.Display.DrawArrow(Line(sp, ep), color, 20, 0)

            # draw face --------------------------------------------------------
            face_coordinates = [
                xyz_dict[vkey] for vkey in cell.face_vertices(fkey)
            ]
            face_coordinates.append(face_coordinates[0])
            polygon_xyz = [Point3d(*xyz) for xyz in face_coordinates]

            e.Display.DrawPolyline(polygon_xyz, black, 2)

            if fkey == face:
                e.Display.DrawPolyline(polygon_xyz, black, 4)
                e.Display.DrawPolygon(polygon_xyz, color, filled=True)

            # display force magnitudes -----------------------------------------
            vector = add_vectors(vector,
                                 scale_vector(normalize_vector(normal), 0.75))
            xyz = add_vectors(center, vector)
            if fkey == face:
                color = black

            e.Display.DrawDot(Point3d(*xyz), str(round(area, 2)), color, white)
示例#15
0
def GetPlanks(name):

    # ==============================================================================
    # BGet Vertices on the boundary based on the name
    # ==============================================================================

    SOUTH = list(cablenet.vertices_where({'constraint': name}))
    boundary = list(cablenet.vertices_on_boundary(ordered=True))
    SOUTH[:] = [key for key in boundary if key in SOUTH]

    # ==============================================================================
    # Boundary plane
    # ==============================================================================

    a = cablenet.vertex_coordinates(SOUTH[0])
    b = cablenet.vertex_coordinates(SOUTH[-1])

    xaxis = subtract_vectors(b, a)
    yaxis = [0, 0, 1.0]
    zaxis = cross_vectors(xaxis, yaxis)
    xaxis = cross_vectors(yaxis, zaxis)

    frame = Frame(a, xaxis, yaxis)

    point = add_vectors(frame.point, scale_vector(frame.zaxis, OFFSET))
    normal = frame.zaxis
    plane = point, normal

    # ==============================================================================
    # Intersections
    # ==============================================================================

    intersections = []
    for key in SOUTH:
        a = cablenet.vertex_coordinates(key)
        r = cablenet.residual(key)
        b = add_vectors(a, r)
        x, y, z = intersection_line_plane((a, b), plane)

        intersections.append(Point(x, y, z))

    # ==============================================================================
    # Bounding boxes
    # ==============================================================================

    limitLength = 2
    limitSmall = 0.12
    frame_box_len_All = []

    start = 0
    end = start + 2  #len(intersections)

    #print("start " + str(start))

    while end <= len(intersections):

        frame_box_len = []
        flag = True
        while (flag and end <= len(intersections)):

            #print((str)(start) + " " + (str)(end))
            #print("number of points " + str(start) + "-" + str(end) )

            frame_box_lenTemp = GetBoundingBox(pca_numpy, intersections,
                                               PADDING, start, end, frame)

            numOfPts = end - start
            """
            if(numOfPts==2):
                end+=1
                continue
            """
            #if(numOfPts==2):
            """
            print(frame_box_lenTemp)
            frame_box_len = frame_box_lenTemp
            end+=1
            break
            """
            """
            if(frame_box_lenTemp[2]>limitLength):
                flag = False
                print("end" + str(end))
                break
            """
            #Check the widht of the plank
            #print(frame_box_lenTemp[2])
            if (frame_box_lenTemp[3] > limitSmall
                    or frame_box_lenTemp[2] > limitLength):
                flag = False
                #print("end" + str(end))
                break
            """
            if(frame_box_lenTemp[3]>limitSmall and frame_box_lenTemp[2]>limitLength):
                flag = False
                print("end" + str(end))
                break
            """

            frame_box_len = frame_box_lenTemp
            end += 1

        start = end - 2
        end = start + 2
        frame_box_len_All.append(frame_box_len)
        #print("start " + str(start))

    return [frame_box_len_All, intersections]
示例#16
0
文件: boundary.py 项目: tetov/ITA19
point = add_vectors(frame.point, scale_vector(frame.zaxis, OFFSET))
normal = frame.zaxis
plane = point, normal

# ==============================================================================
# Compute the intersections of the residual force vectors at the boundary
# vertices with the previously defined intersection plane.
# ==============================================================================

intersections = []

for key in SOUTH:
    a = cablenet.vertex_coordinates(key)
    r = cablenet.residual(key)
    b = add_vectors(a, r)
    x = intersection_line_plane((a, b), plane)

    intersections.append(x)

# ==============================================================================
# Select the first 6 vertices of the boundary for the first segment of the
# supporting structure. Compute a local frame for the selected vertices using a
# PCA of the vertex locations.
# ==============================================================================

points = intersections[:6]

origin, axes, values = pca_numpy(points)
frame1 = Frame(origin, axes[0], axes[1])

# ==============================================================================
    # artist.draw()

    # # # ==============================================================================
    # # # Compute the intersections of the residual force vectors at the boundary
    # # # vertices with the previously defined intersection plane.
    # # # ==============================================================================

    intersections_front = []
    intersections_back = []
    pca_points = []

    for key in l:
        a = cablenet.vertex_coordinates(key)
        r = cablenet.residual(key)
        b = add_vectors(a, r)
        x_front = intersection_line_plane((a, b), plane_front)
        x_back = intersection_line_plane((a, b), plane_back)
        move_point_to_front = add_vectors(
            x_back, scale_vector(frame_0.zaxis, -THICKNESS))

        intersections_front.append(x_front)
        intersections_back.append(x_back)
        pca_points.append(x_front)
        pca_points.append(move_point_to_front)

    PointArtist.draw_collection(intersections_back,
                                layer=name + "::Intersections_back",
                                clear=True)
    PointArtist.draw_collection(pca_points,
                                layer=name + "::Intersections_front",
                                clear=True)