Ejemplo n.º 1
0
def area_polygon(polygon):
    """Compute the area of a polygon.

    Parameters
    ----------
    polygon : sequence
        The XYZ coordinates of the vertices/corners of the polygon.
        The vertices are assumed to be in order.
        The polygon is assumed to be closed:
        the first and last vertex in the sequence should not be the same.

    Returns
    -------
    float
        The area of the polygon.

    """
    o = centroid_points(polygon)
    u = subtract_vectors(polygon[-1], o)
    v = subtract_vectors(polygon[0], o)
    a = 0.5 * length_vector(cross_vectors(u, v))
    for i in range(0, len(polygon) - 1):
        u = v
        v = subtract_vectors(polygon[i + 1], o)
        a += 0.5 * length_vector(cross_vectors(u, v))
    return a
Ejemplo n.º 2
0
def normal_polygon(points, unitized=True):
    """Compute the normal of a polygon defined by a sequence of points.

    Parameters:
        points (sequence): A sequence of points.

    Returns:
        list: The normal vector.

    Raises:
        ValueError: If less than three points are provided.

    Notes:
        The points in the list should be unique. For example, the first and last
        point in the list should not be the same.

    """
    p = len(points)
    assert p > 2, "At least three points required"
    nx = 0
    ny = 0
    nz = 0
    o = centroid_points(points)
    a = subtract_vectors(points[-1], o)
    for i in range(p):
        b = subtract_vectors(points[i], o)
        n = cross_vectors(a, b)
        a = b
        nx += n[0]
        ny += n[1]
        nz += n[2]
    if not unitized:
        return nx, ny, nz
    l = length_vector([nx, ny, nz])
    return nx / l, ny / l, nz / l
Ejemplo n.º 3
0
 def calculate_point(self, v_key):
     cons = self.connectors(v_key)
     pts = []
     for con in cons:
         points_1 = self.struct_bar.vertex[con[0]]["axis_endpoints"]
         points_2 = self.struct_bar.vertex[con[1]]["axis_endpoints"]
         dpp = dropped_perpendicular_points(points_1[0], points_1[1],
                                            points_2[0], points_2[1])
         pts.append(centroid_points(
             dpp))  # contact point is the mid point of P_{i} and P_{Ci}
     # ? why take centroid again?
     contact_pt = centroid_points(pts)
     self.vertex[v_key].update({
         "x": contact_pt[0],
         "y": contact_pt[1],
         "z": contact_pt[2],
         "point_xyz": contact_pt
     })
     return contact_pt
Ejemplo n.º 4
0
def normal_polygon(polygon, unitized=True):
    """Compute the normal of a polygon defined by a sequence of points.

    Parameters
    ----------
    polygon : list of list
        A list of polygon point coordinates.

    Returns
    -------
    list
        The normal vector.

    Raises
    ------
    ValueError
        If less than three points are provided.

    Notes
    -----
    The points in the list should be unique. For example, the first and last
    point in the list should not be the same.

    """
    p = len(polygon)

    assert p > 2, "At least three points required"

    nx = 0
    ny = 0
    nz = 0

    o = centroid_points(polygon)
    a = polygon[-1]
    oa = subtract_vectors(a, o)

    for i in range(p):
        b = polygon[i]
        ob = subtract_vectors(b, o)
        n = cross_vectors(oa, ob)
        oa = ob

        nx += n[0]
        ny += n[1]
        nz += n[2]

    if not unitized:
        return nx, ny, nz

    l = length_vector([nx, ny, nz])

    return nx / l, ny / l, nz / l
Ejemplo n.º 5
0
def calculate_offset_pos_two_side_two_point_locked(b_struct, v_key, vecs_con_1,
                                                   vecs_con_2, pts_con_1,
                                                   pts_con_2, d_o_1, d_o_2):
    """calculate offsetted plane when the bar's both ends have two contact points

    """
    assert len(vecs_con_1) == 2 and len(pts_con_1) == 2
    assert len(vecs_con_2) == 2 and len(pts_con_2) == 2

    map(normalize_vector, vecs_con_1)
    map(normalize_vector, vecs_con_2)
    v1_1, v1_2 = vecs_con_1
    v2_1, v2_2 = vecs_con_2
    pt_1_1, pt_1_2 = pts_con_1
    pt_2_1, pt_2_2 = pts_con_2

    vm_1 = scale_vector(normalize_vector(add_vectors(v1_1, v1_2)), -1. * d_o_1)
    # original contact point (assuming two bars have the same radius)
    pt_1 = centroid_points([pt_1_1, pt_1_2])
    pt_1_new = translate_points([pt_1], vm_1)[0]

    vm_2 = scale_vector(normalize_vector(add_vectors(v2_1, v2_2)), -1. * d_o_2)
    pt_2 = centroid_points([pt_2_1, pt_2_2])
    pt_2_new = translate_points([pt_2], vm_2)[0]

    vec_x_new = normalize_vector(vector_from_points(pt_1_new, pt_2_new))
    x_ax = b_struct.vertex[v_key]["gripping_plane"][1]

    if not angle_vectors(x_ax, vec_x_new, deg=True) < 90:
        vec_x_new = scale_vector(vec_x_new, -1.)

    pt_o = b_struct.vertex[v_key]["gripping_plane"][0]
    y_ax = b_struct.vertex[v_key]["gripping_plane"][2]
    vec_z = cross_vectors(vec_x_new, y_ax)
    l_n = (pt_1_new, pt_2_new)
    pt_o_n = closest_point_on_line(pt_o, l_n)

    return pt_o_n, vec_x_new, y_ax, vec_z
Ejemplo n.º 6
0
def offset_polyline(polyline, distance, normal=[0., 0., 1.]):
    """Offset a polyline by a distance.

    Parameters:
        polyline (sequence of sequence of floats): The XYZ coordinates of the
            vertices of a polyline.
        distance (float or list of tuples of floats): The offset distance as float.
            A single value determines a constant offset globally. Alternatively, pairs of local
            offset values per line segment can be used to create variable offsets.
            Distance > 0: offset to the "left", distance < 0: offset to the "right"
        normal (tuple): The normal of the offset plane.

    Returns:
        offset polyline (sequence of sequence of floats): The XYZ coordinates of the resulting polyline.

    """

    if isinstance(distance, list) or isinstance(distance, tuple):
        distances = distance
        if len(distances) < len(polyline):
            distances = distances + [distances[-1]
                                     ] * (len(polyline) - len(distances) - 1)
    else:
        distances = [[distance, distance]] * len(polyline)

    lines = [polyline[i:i + 2] for i in range(len(polyline[:-1]))]
    lines_offset = []
    for i, line in enumerate(lines):
        lines_offset.append(offset_line(line, distances[i], normal))

    polyline_offset = []
    polyline_offset.append(lines_offset[0][0])
    for i in range(len(lines_offset[:-1])):
        intx_pt1, intx_pt2 = intersection_line_line(lines_offset[i],
                                                    lines_offset[i + 1])

        if intx_pt1 and intx_pt2:
            polyline_offset.append(centroid_points([intx_pt1, intx_pt2]))
        else:
            polyline_offset.append(lines_offset[i][0])
    polyline_offset.append(lines_offset[-1][1])
    return polyline_offset
Ejemplo n.º 7
0
 def centroid(self):
     """int: The centroid of the polygon."""
     return Point(* centroid_points(self.points))
Ejemplo n.º 8
0
    from compas_plotters import Plotter

    plotter = Plotter(figsize=(10, 7))

    points = [[0, 0, 0], [1.0, 0, 0], [1.0, 1.0, 0], [0.5, 0.0, 0],
              [0, 1.0, 0]]
    polygon = points[::-1]

    print(polygon)
    print(area_polygon(polygon))

    n = normal_polygon(polygon, unitized=False)
    print(n)

    if n[2] > 0:
        color = '#ff0000'
    else:
        color = '#0000ff'

    polygons = [{'points': polygon}]
    points = [{
        'pos': centroid_points(polygon),
        'radius': 0.025,
        'facecolor': color
    }]

    plotter.draw_polygons(polygons)
    plotter.draw_points(points)

    plotter.show()
Ejemplo n.º 9
0
def offset_polygon(polygon, distance):
    """Offset a polygon (closed) by a distance.

    Parameters:
        polygon (sequence of sequence of floats): The XYZ coordinates of the
            corners of the polygon. The first and last coordinates must be identical.
        distance (float or list of tuples of floats): The offset distance as float.
            A single value determines a constant offset globally. Alternatively, pairs of local
            offset values per line segment can be used to create variable offsets.
            Distance > 0: offset to the outside, distance < 0: offset to the inside

    Returns:
        offset polygon (sequence of sequence of floats): The XYZ coordinates of the
            corners of the offset polygon. The first and last coordinates are identical.

    Note:
        The offset direction is determined by the normal of the polygon. The
        algorithm works also for spatial polygons that do not perfectly fit a plane.

    Examples:

        .. code-block:: python

            polygon = [
                (0.0, 0.0, 0.0),
                (3.0, 0.0, 1.0),
                (3.0, 3.0, 2.0),
                (1.5, 1.5, 2.0),
                (0.0, 3.0, 1.0),
                (0.0, 0.0, 0.0)
                ]

            distance = 0.5 # constant offset
            polygon_offset = offset_polygon(polygon, distance)
            print(polygon_offset)

            distance = [
                (0.1, 0.2),
                (0.2, 0.3),
                (0.3, 0.4),
                (0.4, 0.3),
                (0.3, 0.1)
                ] # variable offset
            polygon_offset = offset_polygon(polygon, distance)
            print(polygon_offset)

    """
    normal = normal_polygon(polygon)

    if isinstance(distance, list):
        distances = distance
        if len(distances) < len(polygon):
            distances = distances + [distances[-1]] * (len(polygon) - len(distances) - 1)
    else:
        distances = [[distance, distance]] * len(polygon)

    lines = [polygon[i:i + 2] for i in xrange(len(polygon[:-1]))]
    lines_offset = []
    for i, line in enumerate(lines):
        lines_offset.append(offset_line(line, distances[i], normal))

    polygon_offset = []

    for i in xrange(len(lines_offset)):
        intx_pt1, intx_pt2 = intersection_line_line(lines_offset[i - 1], lines_offset[i])

        if intx_pt1 and intx_pt2:
            polygon_offset.append(centroid_points([intx_pt1, intx_pt2]))
        else:
            polygon_offset.append(lines_offset[i][0])

    polygon_offset.append(polygon_offset[0])
    return polygon_offset
Ejemplo n.º 10
0
def area_polygon(polygon):
    """Compute the area of a polygon.

    Parameters
    ----------
    polygon : sequence
        The XYZ coordinates of the vertices/corners of the polygon.
        The vertices are assumed to be in order.
        The polygon is assumed to be closed:
        the first and last vertex in the sequence should not be the same.

    Returns
    -------
    float
        The area of the polygon.

    Examples
    --------
    .. plot::
        :include-source:

        from compas.geometry import area_polygon
        from compas_plotters import Plotter

        plotter = Plotter()

        polygon = [
            [0.0, 0.0, 0.0],
            [1.0, 0.0, 0.0],
            [1.0, 1.0, 0.0],
            [0.0, 1.0, 0.0]
        ]

        area_polygon(polygon)

        # 1.0

        plotter.draw_polygons([{'points': polygon}])
        plotter.show()

    .. plot::
        :include-source:

        from compas.geometry import area_polygon
        from compas_plotters import Plotter

        plotter = Plotter()

        polygon = [
            [0.0, 0.0, 0.0],
            [1.0, 0.0, 0.0],
            [1.0, 1.0, 0.0],
            [0.5, 0.0, 0.0],
            [0.0, 1.0, 0.0]
        ]

        area_polygon(polygon)

        # 0.5

        plotter.draw_polygons([{'points': polygon}])
        plotter.show()

    """
    o = centroid_points(polygon)
    a = polygon[-1]
    b = polygon[0]
    oa = subtract_vectors(a, o)
    ob = subtract_vectors(b, o)

    n0 = cross_vectors(oa, ob)

    area = 0.5 * length_vector(n0)

    for i in range(0, len(polygon) - 1):
        oa = ob
        b = polygon[i + 1]
        ob = subtract_vectors(b, o)
        n = cross_vectors(oa, ob)

        if dot_vectors(n, n0) > 0:
            area += 0.5 * length_vector(n)
        else:
            area -= 0.5 * length_vector(n)

    return area
Ejemplo n.º 11
0
def volume_polyhedron(polyhedron):
    r"""Compute the volume of a polyhedron represented by a closed mesh.

    Parameters
    ----------
    polyhedron : tuple
        The vertices and faces of the polyhedron.

    Returns
    -------
    float
        The volume of the polyhedron.

    Notes
    -----
    This implementation is based on the divergence theorem, the fact that the
    *area vector* is constant for each face, and the fact that the area of each
    face can be computed as half the length of the cross product of two adjacent
    edge vectors [1]_.

    .. math::
        :nowrap:

        \begin{align}
            V  = \int_{P} 1
              &= \frac{1}{3} \int_{\partial P} \mathbf{x} \cdot \mathbf{n} \\
              &= \frac{1}{3} \sum_{i=0}^{N-1} \int{A_{i}} a_{i} \cdot n_{i} \\
              &= \frac{1}{6} \sum_{i=0}^{N-1} a_{i} \cdot \hat n_{i}
        \end{align}

    Warning
    -------
    The volume computed by this funtion is only correct if the polyhedron is convex,
    has planar faces, and is positively oriented (all face normals point outwards).

    References
    ----------
    .. [1] Nurnberg, R. *Calculating the area and centroid of a polygon in 2d*.
           Available at: http://wwwf.imperial.ac.uk/~rn/centroid.pdf

    """
    xyz, faces = polyhedron

    V = 0
    for vertices in faces:
        if len(vertices) == 3:
            triangles = [vertices]
        else:
            centroid = centroid_points([xyz[i] for i in vertices])
            i = len(xyz)
            xyz.append(centroid)
            triangles = []
            for u, v in pairwise(vertices + vertices[0:1]):
                triangles.append([i, u, v])

        for u, v, w in triangles:
            a = xyz[u]
            b = xyz[v]
            c = xyz[w]
            ab = subtract_vectors(b, a)
            ac = subtract_vectors(c, a)
            n = cross_vectors(ab, ac)
            V += dot_vectors(a, n)
    return V / 6.
Ejemplo n.º 12
0
def third_tangent(b_struct,
                  b_v_old,
                  b_v1,
                  b3_1,
                  b3_2,
                  pt_mean_3,
                  max_len,
                  b_v3_1,
                  b_v3_2,
                  pt_mean,
                  radius,
                  b_v0_n=None,
                  check_collision=False):

    line_1 = b_struct.vertex[b_v_old]["axis_endpoints"]
    line_2 = b_struct.vertex[b_v1]["axis_endpoints"]

    b1 = b_struct.vertex[b_v_old]
    b2 = b_struct.vertex[b_v1]

    pt_b_1 = line_1[0]
    pt_b_2 = line_2[0]
    pt_b_3 = b3_1["axis_endpoints"][0]
    pt_b_4 = b3_2["axis_endpoints"][0]
    l_1 = normalize_vector(vector_from_points(line_1[0], line_1[1]))
    l_2 = normalize_vector(vector_from_points(line_2[0], line_2[1]))
    l_3 = normalize_vector(
        vector_from_points(b3_1["axis_endpoints"][0],
                           b3_1["axis_endpoints"][1]))
    l_4 = normalize_vector(
        vector_from_points(b3_2["axis_endpoints"][0],
                           b3_2["axis_endpoints"][1]))

    pts_axis_1 = dropped_perpendicular_points(line_1[0], line_1[1], line_2[0],
                                              line_2[1])
    pt_axis_1 = centroid_points(pts_axis_1)
    pts_axis_2 = dropped_perpendicular_points(b3_1["axis_endpoints"][0],
                                              b3_1["axis_endpoints"][1],
                                              b3_2["axis_endpoints"][0],
                                              b3_2["axis_endpoints"][1])
    pt_axis_2 = centroid_points(pts_axis_2)
    pt_mid = centroid_points((pt_axis_1, pt_axis_2))
    axis = vector_from_points(pt_axis_1, pt_axis_2)
    ex = normalize_vector(cross_vectors(normalize_vector(axis), (1, 0, 0)))
    ey = normalize_vector(cross_vectors(normalize_vector(axis), ex))
    bounds = (-100.0, 100.0)
    args = pt_mid, ex, ey, radius, pt_b_1, l_1, pt_b_2, l_2, pt_b_3, l_3, pt_b_4, l_4, bounds

    # solutions_1     = []
    # solutions_2     = []
    # pts_3           = []

    if check_collision == False:
        if b_v0_n:
            ind_1 = b_struct.vertex[b_v0_n]["index_sol"][0]
            ind_2 = b_struct.vertex[b_v0_n]["index_sol"][1]
        else:
            ind_1 = 0
            ind_2 = 0

        # args = pt_mid, ex, ey, radius, pt_b_1, l_1, pt_b_2, l_2, pt_b_3, l_3, pt_b_4, l_4, bounds, ind_1, ind_2
        # xfunc = XFunc('coop_assembly.help_functions.tangents.solve_third_tangent', radius'C:\Users\parascho\Documents\git_repos')
        # xfunc(pt_mid, ex, ey, radius, pt_b_1, l_1, pt_b_2, l_2, pt_b_3, l_3, pt_b_4, l_4, bounds, ind_1, ind_2)
        # ret_stt = xfunc.data
        ## ret_stt = solve_third_tangent(*args)

        ret_stt = solve_third_tangent(pt_mid, ex, ey, radius, pt_b_1, l_1,
                                      pt_b_2, l_2, pt_b_3, l_3, pt_b_4, l_4,
                                      bounds, ind_1, ind_2)

        # if max(b_struct.vertex.keys()) == 67: print("args", args)

        if ret_stt:
            pt3, vec_l1, vec_l2, ang_check = ret_stt
        else:
            return None

        # pts_3.append(pt3)
        # solutions_1.append(vec_l1)
        # solutions_2.append(vec_l2)
        solution_1 = vec_l1
        solution_2 = vec_l2

        test_1 = check_length_sol_one(solution_2, pt_mean_3, pt3, b3_1, b3_2,
                                      b_v3_1, b_v3_2, b_struct)
        test_2 = check_length_sol_one(solution_1, pt_mean_3, pt3, b1, b2,
                                      b_v_old, b_v1, b_struct)

        if not test_1 or not test_2:
            return None

        # for n in test_1:
        #     for m in test_2:
        #         if n[4] == m[4]:
        #             vec_sol_31, l31, pts_b3_11, pts_b3_21, ind = n
        #             vec_sol_32, l32, pts_b3_12, pts_b3_22, ind_2 = m
        vec_sol_31, l31, pts_b3_11, pts_b3_21 = test_1
        vec_sol_32, l32, pts_b3_12, pts_b3_22 = test_2

        pt3_e1 = add_vectors(pt3, scale_vector(vec_sol_31, l31))
        pt3_e2 = add_vectors(pt3, scale_vector(vec_sol_32, -1 * l32))

        end_pts_0 = (pt3_e2, pt3_e1)

    else:
        bool_test = False
        for i in range(4):
            for j in range(4):
                ind_1 = i
                ind_2 = j

                args = pt_mid, ex, ey, radius, pt_b_1, l_1, pt_b_2, l_2, pt_b_3, l_3, pt_b_4, l_4, bounds, ind_1, ind_2
                ret_stt = solve_third_tangent(*args)
                if ret_stt:
                    pt3, vec_l1, vec_l2, ang_check = ret_stt
                else:
                    return None

                # pts_3.append(pt3)
                # solutions_1.append(vec_l1)
                # solutions_2.append(vec_l2)
                solution_1 = vec_l1
                solution_2 = vec_l2

                #for j in range(4):
                test_1 = check_length_sol_one(solution_2, pt_mean_3, pt3, b3_1,
                                              b3_2, b_v3_1, b_v3_2, b_struct)
                test_2 = check_length_sol_one(solution_1, pt_mean_3, pt3, b1,
                                              b2, b_v_old, b_v1, b_struct)

                if not test_1 or not test_2:
                    return None

                vec_sol_31, l31, pts_b3_11, pts_b3_21 = test_1
                vec_sol_32, l32, pts_b3_12, pts_b3_22 = test_2

                pt3_e1 = add_vectors(pt3, scale_vector(vec_sol_31, l31))
                pt3_e2 = add_vectors(pt3, scale_vector(vec_sol_32, -1 * l32))

                end_pts_0 = (pt3_e2, pt3_e1)

                ext_len = 30
                end_pts_0 = (add_vectors(
                    pt3_e2,
                    scale_vector(
                        normalize_vector(vector_from_points(pt3_e1, pt3_e2)),
                        ext_len)),
                             add_vectors(
                                 pt3_e1,
                                 scale_vector(
                                     normalize_vector(
                                         vector_from_points(pt3_e2, pt3_e1)),
                                     ext_len)))

                bool_col = check_colisions(b_struct,
                                           end_pts_0,
                                           radius,
                                           bar_nb=b_v0_n)

                if bool_col == True:
                    end_pts_check = b_struct.vertex[b_v3_1]["axis_endpoints"]
                    bool_col = check_colisions(b_struct,
                                               end_pts_check,
                                               radius,
                                               bar_nb=b_v0_n,
                                               bar_checking=b_v3_1)
                    if bool_col == True:
                        end_pts_check = b_struct.vertex[b_v3_2][
                            "axis_endpoints"]
                        bool_col = check_colisions(b_struct,
                                                   end_pts_check,
                                                   radius,
                                                   bar_nb=b_v0_n,
                                                   bar_checking=b_v3_2)

                # bool_col = True
                if bool_col == False:
                    print("COLLIDE", len(b_struct.vertex))
                if i == 3 and j == 3 and bool_col == False:
                    print("NO TANGENT 3 FOUND IN ONE BAR COMBINATION")
                    return None
                if bool_col == True:
                    bool_test = True
                    break
            if bool_test == True: break

    # end_pts_0 = [map(float, p) for p in end_pts_0]
    vec_x, vec_y, vec_z = calculate_coord_sys(end_pts_0, pt_mean)
    # pt_o        = centroid_points(end_pts_0)
    if not b_v0_n:
        # b_v0    = b_struct.add_bar(0, end_pts_0, "tube", (2*radius, 2.0), vec_z)
        b_v0 = b_struct.add_bar(0, end_pts_0, "tube", (25.0, 2.0), vec_z)
    else:
        b_v0 = b_v0_n
        b_struct.vertex[b_v0].update({"axis_endpoints": end_pts_0})

    b_struct.vertex[b_v0].update({"index_sol": [ind_1, ind_2]})
    # b_struct.vertex[b_v0].update({"gripping_plane_no_offset":(pt_o, vec_x, vec_y, vec_z)})

    # calculate_gripping_plane(b_struct, b_v0, pt_mean)
    b_struct.vertex[b_v0].update({"mean_point": pt_mean})

    b3_1.update({"axis_endpoints": pts_b3_11})
    b3_2.update({"axis_endpoints": pts_b3_21})
    if not b_v0_n:
        b_struct.connect_bars(b_v0, b_v3_1)
        b_struct.connect_bars(b_v0, b_v3_2)

    dpp_1 = dropped_perpendicular_points(
        b_struct.vertex[b_v0]["axis_endpoints"][0],
        b_struct.vertex[b_v0]["axis_endpoints"][1],
        b_struct.vertex[b_v3_1]["axis_endpoints"][0],
        b_struct.vertex[b_v3_1]["axis_endpoints"][1])
    dpp_2 = dropped_perpendicular_points(
        b_struct.vertex[b_v0]["axis_endpoints"][0],
        b_struct.vertex[b_v0]["axis_endpoints"][1],
        b_struct.vertex[b_v3_2]["axis_endpoints"][0],
        b_struct.vertex[b_v3_2]["axis_endpoints"][1])

    #     b_struct.edge[b_v0][b_v3_1].update({"endpoints":[dpp_1[0], dpp_1[1]]})
    #     b_struct.edge[b_v0][b_v3_2].update({"endpoints":[dpp_2[0], dpp_2[1]]})
    k_1 = list(b_struct.edge[b_v0][b_v3_1]["endpoints"].keys())[0]
    k_2 = list(b_struct.edge[b_v0][b_v3_2]["endpoints"].keys())[0]
    b_struct.edge[b_v0][b_v3_1]["endpoints"].update(
        {k_1: (dpp_1[0], dpp_1[1])})
    b_struct.edge[b_v0][b_v3_2]["endpoints"].update(
        {k_2: (dpp_2[0], dpp_2[1])})

    return b_v0, pt3, end_pts_0
Ejemplo n.º 13
0
def bestfit_plane_from_points(points):
    """Fit a plane to a list of (more than three) points.

    Parameters
    ----------
    points : list of list
        A list of points represented by their XYZ coordinates.

    Returns
    -------
    plane : tuple
        Base point and normal vector (normalized).

    References
    ----------
    http://www.ilikebigbits.com/blog/2015/3/2/plane-from-points

    Warning
    -------
    This method will minimize the squares of the residuals as perpendicular
    to the main axis, not the residuals perpendicular to the plane. If the
    residuals are small (i.e. your points all lie close to the resulting plane),
    then this method will probably suffice. However, if your points are more
    spread then this method may not be the best fit.

    See also
    --------
    compas.numerical.geometry.bestfit_plane

    Examples
    --------
    >>>

    """
    centroid = centroid_points(points)

    xx, xy, xz = 0., 0., 0.
    yy, yz, zz = 0., 0., 0.

    for point in points:
        rx, ry, rz = subtract_vectors(point, centroid)
        xx += rx * rx
        xy += rx * ry
        xz += rx * rz
        yy += ry * ry
        yz += ry * rz
        zz += rz * rz

    det_x = yy * zz - yz * yz
    det_y = xx * zz - xz * xz
    det_z = xx * yy - xy * xy

    det_max = max(det_x, det_y, det_z)

    if det_max == det_x:
        a = (xz * yz - xy * zz) / det_x
        b = (xy * yz - xz * yy) / det_x
        normal = (1., a, b)
    elif det_max == det_y:
        a = (yz * xz - xy * zz) / det_y
        b = (xy * xz - yz * xx) / det_y
        normal = (a, 1., b)
    else:
        a = (yz * xy - xz * yy) / det_z
        b = (xz * xy - yz * xx) / det_z
        normal = (a, b, 1.)

    return centroid, normalize_vector(normal)
Ejemplo n.º 14
0
def add_tetra(o_struct,
              b_struct,
              connected_edges_from_vert,
              new_vertex_pt,
              new_vertex_id,
              radius,
              bool_add=True,
              b_vert_ids=None,
              o_v_key=None,
              correct=True,
              check_collision=False):
    """adds a new point and tetrahedron to the structure
        input: nodes, bars from o_struct as vertex_key_integer and edge_vertex_key_tuples

    .. image:: ../images/three_bar_group_generation.png
        :scale: 60 %
        :align: center

    Parameters
    ----------
    o_struct : OverallStructure
        [description]
    b_struct : BarStructure
        [description]
    tri_node_ids : list of three int
    connected_edges_from_vert : dict
        {OverallS vertex key : list of OverallS's edges}
        dict keys: OverallStructure's vertex id triplets, representing the "ideal vertex" where multiple bars meet together.
        dict value: each entry is a list of OverallS's edges connected to ideal vertex tri_node_ids[0], each representing a potential new bar (edges in OverallS represents bars)
    new_vertex_pt : list, three floats
        [x, y, z] coordinate of the newly added ideal vertex in OverallS.
    new_vertex_id : int
        vertex key of the newly added ideal vertex in OverallS.
    radius : float
        radius of the bar, in millimeter
    bool_add : bool, optional
        generate new vertex, not using given b_vi, by default True
    b_vert_ids : list of three ints, optional
        BarS vertex ids, if specified, b_struct's corresponding vertices attributes will be updated, by default None
    o_v_key : int, optional
        if specified, o_struct's corresponding vertex pt will be updated, by default None
    correct : bool, optional
        perform angle/distance based vertex correction if True, by default True
    check_collision : bool, optional
        perform collision-based correction if True, by default False
    """

    # len_vec_min     = 500
    # len_vec_max     = 1400
    # len_vec         = (random.random()*(len_vec_max - len_vec_min))+len_vec_min
    max_len = 1800
    assert bool_add or (b_vert_ids is not None and len(b_vert_ids) == 3)
    assert len(connected_edges_from_vert) == 3

    tri_node_ids = list(connected_edges_from_vert.keys())
    comb_bars_1, comb_bars_2, comb_bars_3 = connected_edges_from_vert.values()

    # * finding the mean point?
    jnd = 0
    bars1 = comb_bars_1[jnd]
    bars2 = comb_bars_2[jnd]
    bars3 = comb_bars_3[jnd]
    print('bars 1 {} | bars 2 {} | bars 3 {}'.format(bars1, bars2, bars3))

    # vertex id in BarS
    # TODO: write a function to find mean point given bar ids
    # two bars at vertex 0
    b_v1_1 = o_struct.edge[bars1[0][0]][bars1[0][1]]["vertex_bar"]
    b1_1 = b_struct.vertex[b_v1_1]
    b_v1_2 = o_struct.edge[bars1[1][0]][bars1[1][1]]["vertex_bar"]
    b1_2 = b_struct.vertex[b_v1_2]

    # two bars at vertex 1
    b_v2_1 = o_struct.edge[bars2[0][0]][bars2[0][1]]["vertex_bar"]
    b2_1 = b_struct.vertex[b_v2_1]
    b_v2_2 = o_struct.edge[bars2[1][0]][bars2[1][1]]["vertex_bar"]
    b2_2 = b_struct.vertex[b_v2_2]

    # two bars at vertex 2
    b_v3_1 = o_struct.edge[bars3[0][0]][bars3[0][1]]["vertex_bar"]
    b3_1 = b_struct.vertex[b_v3_1]
    b_v3_2 = o_struct.edge[bars3[1][0]][bars3[1][1]]["vertex_bar"]
    b3_2 = b_struct.vertex[b_v3_2]

    # center points of the bar axes to obtain the central point of the base triangle
    dpp1 = dropped_perpendicular_points(b1_1["axis_endpoints"][0],
                                        b1_1["axis_endpoints"][1],
                                        b1_2["axis_endpoints"][0],
                                        b1_2["axis_endpoints"][1])
    pt_mean_1 = centroid_points(dpp1)
    dpp2 = dropped_perpendicular_points(b2_1["axis_endpoints"][0],
                                        b2_1["axis_endpoints"][1],
                                        b2_2["axis_endpoints"][0],
                                        b2_2["axis_endpoints"][1])
    pt_mean_2 = centroid_points(dpp2)
    dpp3 = dropped_perpendicular_points(b3_1["axis_endpoints"][0],
                                        b3_1["axis_endpoints"][1],
                                        b3_2["axis_endpoints"][0],
                                        b3_2["axis_endpoints"][1])
    pt_mean_3 = centroid_points(dpp3)

    pt_mean = centroid_points([pt_mean_1, pt_mean_2, pt_mean_3])

    # if new_vertex_pt:
    pt_new = new_vertex_pt
    # check if new point is inside of structure
    # if not new_vertex_pt:
    #     for t in o_struct.tetrahedra:
    #         if len(o_struct.tetrahedra[t]) > 3:
    #             if not o_struct.isOutside(pt_new, t):
    #                 vec_n   = scale_vector(vec_n, -1)
    #                 pt_new  = add_vectors(pt_mean, vec_n)

    if correct:
        pt_new = correct_point(b_struct,
                               o_struct,
                               pt_new, [(b_v1_1, b_v1_2), (b_v2_1, b_v2_2),
                                        (b_v3_1, b_v3_2)],
                               o_v_key=o_v_key)
    pt1 = pt_new

    for j, bar_jnd_1 in enumerate(comb_bars_1):
        bars1 = bar_jnd_1

        b_v1_1 = o_struct.edge[bars1[0][0]][bars1[0][1]]["vertex_bar"]
        b1_1 = b_struct.vertex[b_v1_1]

        b_v1_2 = o_struct.edge[bars1[1][0]][bars1[1][1]]["vertex_bar"]
        b1_2 = b_struct.vertex[b_v1_2]

        if correct:
            pt_new = correct_point(b_struct,
                                   o_struct,
                                   pt_new, [(b_v1_1, b_v1_2), (b_v2_1, b_v2_2),
                                            (b_v3_1, b_v3_2)],
                                   o_v_key=o_v_key)

        # ! is this a mistype? shouldn't we plug in the corrected pt pt_new?
        ret_ft = first_tangent(pt1,
                               b1_1,
                               b1_2,
                               pt_mean_1,
                               max_len,
                               b_v1_1,
                               b_v1_2,
                               b_struct,
                               pt_mean,
                               radius,
                               b_v0_n=None if bool_add else b_v0,
                               check_collision=check_collision)

        if ret_ft:
            b_v0, end_pts_0 = ret_ft
            break
        else:
            # print("tangent 1 not found")
            if j == len(comb_bars_1) - 1:
                # print("no point found for first tangent calculation - 430, add_tetra")
                raise RuntimeError(
                    "no point found for first tangent calculation - 430, add_tetra"
                )

    for j, bar_jnd_2 in enumerate(comb_bars_2):
        bars2 = bar_jnd_2
        b2_1 = b_struct.vertex[o_struct.edge[bars2[0][0]][bars2[0][1]]
                               ["vertex_bar"]]
        b_v2_1 = o_struct.edge[bars2[0][0]][bars2[0][1]]["vertex_bar"]
        b2_2 = b_struct.vertex[o_struct.edge[bars2[1][0]][bars2[1][1]]
                               ["vertex_bar"]]
        b_v2_2 = o_struct.edge[bars2[1][0]][bars2[1][1]]["vertex_bar"]

        if correct:
            pt_new = correct_point(b_struct,
                                   o_struct,
                                   pt_new, [(b_v1_1, b_v1_2), (b_v2_1, b_v2_2),
                                            (b_v3_1, b_v3_2)],
                                   o_v_key=o_v_key)
        if bool_add:
            ret_st = second_tangent(b2_1,
                                    b2_2,
                                    pt_mean_2,
                                    b_v2_1,
                                    b_v2_2,
                                    b_struct,
                                    b_v0,
                                    pt1,
                                    radius,
                                    max_len,
                                    pt_mean,
                                    check_collision=check_collision)
        else:
            ret_st = second_tangent(b2_1,
                                    b2_2,
                                    pt_mean_2,
                                    b_v2_1,
                                    b_v2_2,
                                    b_struct,
                                    b_v0,
                                    pt1,
                                    radius,
                                    max_len,
                                    pt_mean,
                                    b_v1,
                                    check_collision=check_collision)
        if ret_st:
            b_v1, pt2, end_pts_1 = ret_st
            break
        else:
            # print("tangent 2 not found")
            if j == len(comb_bars_2) - 1:
                # print("no point found for second tangent calculation - 430, add_tetra")
                raise RuntimeError(
                    "no point found for second tangent calculation - 430, add_tetra"
                )

    for j, bar_jnd_3 in enumerate(comb_bars_3):
        bars3 = bar_jnd_3
        b3_1 = b_struct.vertex[o_struct.edge[bars3[0][0]][bars3[0][1]]
                               ["vertex_bar"]]
        b_v3_1 = o_struct.edge[bars3[0][0]][bars3[0][1]]["vertex_bar"]
        b3_2 = b_struct.vertex[o_struct.edge[bars3[1][0]][bars3[1][1]]
                               ["vertex_bar"]]
        b_v3_2 = o_struct.edge[bars3[1][0]][bars3[1][1]]["vertex_bar"]

        if correct:
            pt_new = correct_point(b_struct,
                                   o_struct,
                                   pt_new, [(b_v1_1, b_v1_2), (b_v2_1, b_v2_2),
                                            (b_v3_1, b_v3_2)],
                                   o_v_key=o_v_key)
        if bool_add:
            ret_tt = third_tangent(b_struct,
                                   b_v0,
                                   b_v1,
                                   b3_1,
                                   b3_2,
                                   pt_mean_3,
                                   max_len,
                                   b_v3_1,
                                   b_v3_2,
                                   pt_mean,
                                   radius,
                                   check_collision=check_collision)
        else:
            ret_tt = third_tangent(b_struct,
                                   b_v0,
                                   b_v1,
                                   b3_1,
                                   b3_2,
                                   pt_mean_3,
                                   max_len,
                                   b_v3_1,
                                   b_v3_2,
                                   pt_mean,
                                   radius,
                                   b_v2,
                                   check_collision=check_collision)
        if ret_tt:
            b_v2, pt3, end_pts_2 = ret_tt
            break
        else:
            # print("tangent 3 not found")
            if j == len(comb_bars_3) - 1:
                # print("no point found for third tangent calculation - 430, add_tetra")
                raise RuntimeError(
                    "no point found for third tangent calculation - 430, add_tetra"
                )

    # * BarStructure update
    if bool_add:
        # adding contact edge information in BarS
        b_struct.connect_bars(b_v0, b_v1)
        b_struct.connect_bars(b_v1, b_v2)
        b_struct.connect_bars(b_v2, b_v0)
    # contact edge coordinate
    dpp_1 = dropped_perpendicular_points(
        b_struct.vertex[b_v1]["axis_endpoints"][0],
        b_struct.vertex[b_v1]["axis_endpoints"][1],
        b_struct.vertex[b_v2]["axis_endpoints"][0],
        b_struct.vertex[b_v2]["axis_endpoints"][1])
    key = list(b_struct.edge[b_v1][b_v2]["endpoints"].keys())[0]
    b_struct.edge[b_v1][b_v2]["endpoints"].update({key: (dpp_1[0], dpp_1[1])})

    dpp_2 = dropped_perpendicular_points(
        b_struct.vertex[b_v2]["axis_endpoints"][0],
        b_struct.vertex[b_v2]["axis_endpoints"][1],
        b_struct.vertex[b_v0]["axis_endpoints"][0],
        b_struct.vertex[b_v0]["axis_endpoints"][1])
    key = list(b_struct.edge[b_v2][b_v0]["endpoints"].keys())[0]
    b_struct.edge[b_v2][b_v0]["endpoints"].update({key: (dpp_2[0], dpp_2[1])})

    dpp_3 = dropped_perpendicular_points(
        b_struct.vertex[b_v0]["axis_endpoints"][0],
        b_struct.vertex[b_v0]["axis_endpoints"][1],
        b_struct.vertex[b_v1]["axis_endpoints"][0],
        b_struct.vertex[b_v1]["axis_endpoints"][1])
    key = list(b_struct.edge[b_v0][b_v1]["endpoints"].keys())[0]
    b_struct.edge[b_v0][b_v1]["endpoints"].update({key: (dpp_3[0], dpp_3[1])})

    # * OverallStructure update
    if bool_add:
        o_n_new = o_struct.add_node(pt_new, v_key=new_vertex_id)

    ### check length of bar and adjust gripper position ###
    # pt_bar_1    = b_struct.vertex[b_v0]["axis_endpoints"]
    # pt_bar_2    = b_struct.vertex[b_v1]["axis_endpoints"]
    # pt_bar_3    = b_struct.vertex[b_v2]["axis_endpoints"]

    # adjust_gripping_plane(pt_bar_1, pt_new, b_struct, b_v0)
    # adjust_gripping_plane(pt_bar_2, pt_new, b_struct, b_v1)
    # adjust_gripping_plane(pt_bar_3, pt_new, b_struct, b_v2)
    ### ###

    if bool_add:
        o_n1 = tri_node_ids[0]
        o_n2 = tri_node_ids[1]
        o_n3 = tri_node_ids[2]
        o_struct.add_bar(o_n_new, o_n1, b_v0)
        o_struct.add_bar(o_n_new, o_n2, b_v1)
        o_struct.add_bar(o_n_new, o_n3, b_v2)

    # adjust newly added bars' length
    find_bar_ends(b_struct, b_v0)
    find_bar_ends(b_struct, b_v1)
    find_bar_ends(b_struct, b_v2)

    # adjust neighbor bars' length
    # find_bar_ends(b_struct, b_v1_1)
    # find_bar_ends(b_struct, b_v1_2)
    # find_bar_ends(b_struct, b_v2_1)
    # find_bar_ends(b_struct, b_v2_2)
    # find_bar_ends(b_struct, b_v3_1)
    # find_bar_ends(b_struct, b_v3_2)

    return o_struct, b_struct
Ejemplo n.º 15
0
def bestfit_plane(points):
    """Fit a plane to a list of (more than three) points.

    Parameters
    ----------
    points : list of list
        A list of points represented by their XYZ coordinates.

    Returns
    -------
    plane : tuple
        Base point and normal vector (normalized).

    Notes
    -----
    This method will minimize the squares of the residuals as perpendicular
    to the main axis, not the residuals perpendicular to the plane. If the
    residuals are small (i.e. your points all lie close to the resulting plane),
    then this method will probably suffice. However, if your points are more
    spread then this method may not be the best fit. For more information see
    [ernerfeldt2015]_

    References
    ----------
    .. [ernerfeldt2015] Ernerfeldt, E. *Fitting a plane to many points in 3D*.
                        Available at: http://www.ilikebigbits.com/blog/2015/3/2/plane-from-points

    Examples
    --------
    .. code-block:: python

        #

    See also
    --------
    :func:`bestfit_plane_numpy` : Variation using NumPy.

    """
    centroid = centroid_points(points)

    xx, xy, xz = 0., 0., 0.
    yy, yz, zz = 0., 0., 0.

    for point in points:
        rx, ry, rz = subtract_vectors(point, centroid)
        xx += rx * rx
        xy += rx * ry
        xz += rx * rz
        yy += ry * ry
        yz += ry * rz
        zz += rz * rz

    det_x = yy * zz - yz * yz
    det_y = xx * zz - xz * xz
    det_z = xx * yy - xy * xy

    det_max = max(det_x, det_y, det_z)

    if det_max == det_x:
        a = (xz * yz - xy * zz) / det_x
        b = (xy * yz - xz * yy) / det_x
        normal = (1., a, b)
    elif det_max == det_y:
        a = (yz * xz - xy * zz) / det_y
        b = (xy * xz - yz * xx) / det_y
        normal = (a, 1., b)
    else:
        a = (yz * xy - xz * yy) / det_z
        b = (xz * xy - yz * xx) / det_z
        normal = (a, b, 1.)

    return centroid, normalize_vector(normal)
Ejemplo n.º 16
0
def calculate_gripping_plane(b_struct,
                             v,
                             pt_mean,
                             nb_rot=8,
                             nb_trans=8,
                             planes_rot=True,
                             planes_trans=True):
    """calculate gripping planes for a given bar structure and the vertex key (representing a bar)

    Parameters
    ----------
    b_struct : [type]
        [description]
    v : [type]
        [description]
    pt_mean : [type]
        [description]
    nb_rot : int, optional
        number of rotational division, by default 8
    nb_trans : int, optional
        number of translational division, by default 8
    planes_rot : bool, optional
        [description], by default True
    planes_trans : bool, optional
        [description], by default True
    """

    end_pts_0 = b_struct.vertex[v]["axis_endpoints"]
    # local coordinate system
    vec_x, vec_y, vec_z = calculate_coord_sys(end_pts_0, pt_mean)
    # mid point of the bar axis
    pt_o = centroid_points(end_pts_0)

    b_struct.vertex[v].update({"gripping_plane": (pt_o, vec_x, vec_y, vec_z)})
    gripping_plane = b_struct.vertex[v]["gripping_plane"]

    frames_all = []

    if planes_trans == True:
        # extend both end points for 30 mm
        vec_bar = scale_vector(
            normalize_vector(subtract_vectors(end_pts_0[1], end_pts_0[0])), 30)
        pt1 = add_vectors(end_pts_0[0], vec_bar)
        vec_bar = scale_vector(vec_bar, -1)
        pt2 = add_vectors(end_pts_0[1], vec_bar)
        vec_n = subtract_vectors(pt2, pt1)
        len_vec = length_vector(vec_n)
        len_new = len_vec / (nb_trans - 1)

        for i in range(nb_trans):
            origin = add_vectors(
                pt1, scale_vector(normalize_vector(vec_n), len_new * i))
            frame_n = [origin, gripping_plane[1], gripping_plane[2]]
            if not planes_rot:
                frames_all.append(frame_n)
                # if planes_flip == True:
                #     frame_n = [frame_n[0], scale_vector(frame_n[1], -1), scale_vector(frame_n[2], -1)]
                #     frames_all.append(frame_n)
            else:
                ang = math.radians(360 / nb_rot)
                for n in range(nb_rot):
                    gripping_plane = frame_n
                    vecs_n = rotate_points(
                        [gripping_plane[1], gripping_plane[2]],
                        angle=n * ang,
                        axis=subtract_vectors(end_pts_0[1], end_pts_0[0]),
                        origin=(0, 0, 0))
                    frame_n = [gripping_plane[0], vecs_n[0], vecs_n[1]]
                    frames_all.append(frame_n)
                    # if planes_flip == True:
                    #     frame_n = [frame_n[0], scale_vector(frame_n[1], -1), scale_vector(frame_n[2], -1)]
                    #     frames_all.append(frame_n)
    elif planes_rot == True:
        ang = math.radians(360 / nb_rot)
        for n in range(nb_rot):
            vecs_n = rotate_points([gripping_plane[1], gripping_plane[2]],
                                   angle=n * ang,
                                   axis=subtract_vectors(
                                       end_pts_0[1], end_pts_0[0]),
                                   origin=(0, 0, 0))
            frame_n = [gripping_plane[0], vecs_n[0], vecs_n[1]]
            frames_all.append(frame_n)

            # if planes_flip == True:
            #     frame_n = [frame_n[0], scale_vector(frame_n[1], -1), scale_vector(frame_n[2], -1)]
            #     frames_all.append(frame_n)

    for i, f in enumerate(frames_all):
        z_vec = cross_vectors(f[1], f[2])
        frames_all[i].append(z_vec)

    b_struct.vertex[v].update({"gripping_planes_all": frames_all})