Beispiel #1
0
    def gluepath_creator(int_surf, path_width):
        def interval_checker(dimension):
            underflow = dimension % path_width
            if underflow > 0.2:
                no_paths = dimension // path_width + 1
                new_path_width = dimension / no_paths
                return new_path_width
            else:
                return path_width

        wid_gap = int_surf[1] - int_surf[0]
        wid_vec = Vector(wid_gap[0], wid_gap[1], wid_gap[2])
        wid = wid_vec.length
        wid_vec.unitize()
        len_gap = int_surf[2] - int_surf[1]
        len_vec = Vector(len_gap[0], len_gap[1], len_gap[2])
        len = len_vec.length
        len_vec.unitize()
        wid_path = interval_checker(wid)
        len_path = interval_checker(len)
        path_dims = [wid_path, len_path]
        path_points = []
        iteration = 0
        path_unfinished = True
        current_pt = int_surf[0] + scale_vector(
            wid_vec, wid_path / 2) + scale_vector(len_vec, len_path / 2)
        current_vec = len_vec.unitized()
        len_left = len - len_path
        wid_left = wid - wid_path
        dims_left = [len_left, wid_left]
        path_points.append(current_pt)
        R = Rotation.from_axis_and_angle([0, 0, 1], -math.pi / 2)
        while path_unfinished:
            current_index = iteration % 2
            current_dim = dims_left[current_index]
            if iteration > 2:
                current_dim -= path_dims[current_index]
                dims_left[current_index] = current_dim

            if current_dim < path_width * 0.95:
                break
            current_pt = current_pt + scale_vector(current_vec, current_dim)
            path_points.append(current_pt)
            current_vec.transform(R)
            current_vec.unitize()
            iteration += 1
            if not is_point_in_polygon_xy(current_pt, int_surf):
                print("Error: Point not in polygon")

        return path_points
Beispiel #2
0
def offset_line(line, distance, normal=[0., 0., 1.]):
    """Offset a line by a distance.

    Parameters
    ----------
    line : tuple
        Two points defining the line.
    distances : float or tuples of floats
        The offset distance as float.
        A single value determines a constant offset. Alternatively, two
        offset values for the start and end point of the line can be used to
        a create variable offset.
    normal : tuple
        The normal of the offset plane.

    Returns
    -------
    offset line (tuple)
        Two points defining the offset line.

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

        line = [(0.0, 0.0, 0.0), (3.0, 3.0, 0.0)]

        distance = 0.2 # constant offset
        line_offset = offset_line(line, distance)
        print(line_offset)

        distance = [0.2, 0.1] # variable offset
        line_offset = offset_line(line, distance)
        print(line_offset)

    """
    pt1, pt2 = line[0], line[1]
    vec = subtract_vectors(pt1, pt2)
    dir_vec = normalize_vector(cross_vectors(vec, normal))

    if isinstance(distance, list) or isinstance(distance, tuple):
        distances = distance
    else:
        distances = [distance, distance]

    vec_pt1 = scale_vector(dir_vec, distances[0])
    vec_pt2 = scale_vector(dir_vec, distances[1])
    pt1_new = add_vectors(pt1, vec_pt1)
    pt2_new = add_vectors(pt2, vec_pt2)
    return pt1_new, pt2_new
    def board_geometry_setup(self):
        for my_layer in range(self.layer_no):
            if my_layer % 2 == 0:
                my_frame = self.origin_fr
            else:
                my_frame = self.sec_fr

            my_dir1 = normalize_vector(my_frame[1])
            my_dir2 = normalize_vector(my_frame[2])

            # we have to separate i/board_code because of possible exceptions in the centre
            for my_board in self.timberboards[my_layer]:
                dist = my_board.grid_position
                # build the three vectors with which we later find he centre point
                # one advanced case
                layer_standard_length = my_board.layer.characteristic_length

                if my_board.location == "high":
                    if not my_board.supporter:
                        length_attribute_1 = layer_standard_length - my_board.length / 2
                    else:
                        length_attribute_1 = layer_standard_length - my_board.width / 2
                elif my_board.location == "low":
                    if not my_board.supporter:
                        length_attribute_1 = my_board.length / 2
                    else:
                        length_attribute_1 = my_board.width / 2
                else:
                    length_attribute_1 = layer_standard_length / 2

                # position parallel to the boards (if not sup)
                my_vec1 = scale_vector(my_dir1, length_attribute_1)
                # position perpendicular to board direction (if not sup)
                my_vec2 = scale_vector(my_dir2, dist)
                # height vector
                my_vec3 = Vector(
                    0, 0, my_board.layer.z_drop_point - my_board.height / 2)
                my_centre = self.origin_pt + my_vec1 + my_vec2 + my_vec3
                my_board.centre_point = my_centre
                my_board.drop_point = my_centre + Vector(
                    0, 0, my_board.height / 2)
                if not my_board.supporter:
                    my_board.length_vector = normalize_vector(my_vec1)
                    my_board.width_vector = normalize_vector(my_vec2)
                else:
                    my_board.length_vector = normalize_vector(my_vec2)
                    my_board.width_vector = normalize_vector(my_vec1)
                my_board.box_update()
Beispiel #4
0
def polygon_normal_oriented(polygon, unitized=True):
    """Compute the oriented normal of any closed polygon (can be convex, concave or complex).

    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
    -------
    list
        The weighted or unitized normal vector of the polygon.

    """
    p = len(polygon)
    assert p > 2, "At least three points required"
    w          = centroid_points(polygon)
    normal_sum = (0, 0, 0)

    for i in range(-1, len(polygon) - 1):
        u          = polygon[i]
        v          = polygon[i + 1]
        uv         = subtract_vectors(v, u)
        vw         = subtract_vectors(w, v)
        normal     = scale_vector(cross_vectors(uv, vw), 0.5)
        normal_sum = add_vectors(normal_sum, normal)

    if not unitized:
        return normal_sum

    return normalize_vector(normal_sum)
Beispiel #5
0
def tween_points_distance(points1, points2, dist, index=None):
    """Compute an interpolated set of points between two sets of points, at
    a given distance.

    Parameters
    ----------
    points1 : list
        The first set of points
    points2 : list
        The second set of points
    dist : float
        The distance from the first set to the second at which to compute the
        interpolated set.
    index: int
        The index of the point in the first set from which to calculate the
        distance to the second set. If no value is given, the first point will be used.

    Returns
    -------
    list
        List of points

    """
    if not index:
        index = 0
    d = distance_point_point(points1[index], points2[index])
    scale = float(dist) / d
    tweens = []
    for i in range(len(points1)):
        tweens.append(
            add_vectors(
                points1[i],
                scale_vector(vector_from_points(points1[i], points2[i]),
                             scale)))
    return tweens
Beispiel #6
0
def mirror_vector_vector(v1, v2):
    """Mirrors vector about vector.

    Parameters
    ----------
    v1 : [float, float, float] | :class:`compas.geometry.Vector`
        The vector.
    v2 : [float, float, float] | :class:`compas.geometry.Vector`
        The normalized vector as mirror axis

    Returns
    -------
    [float, float, float]
        The mirrored vector.

    Notes
    -----
    For more info, see [1]_.

    References
    ----------
    .. [1] Math Stack Exchange. *How to get a reflection vector?*
           Available at: https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector.

    """
    return subtract_vectors(v1, scale_vector(v2, 2 * dot_vectors(v1, v2)))
Beispiel #7
0
    def draw_facenormals(self, faces=None, color=(0, 255, 255), scale=1.0):
        """Draw the normals of the faces.

        Parameters
        ----------
        faces : list, optional
            A selection of face normals to draw.
            Default is to draw all face normals.
        color : tuple, optional
            The color specification of the normal vectors.
            The default color is cyan, ``(0, 255, 255)``.
        scale : float, optional
            Scale factor for the face normals.
            Default is ``1.0``.

        Returns
        -------
        list
            The GUIDs of the created Rhino objects.

        """
        vertex_xyz = self.vertex_xyz
        faces = faces or list(self.mesh.faces())
        lines = []
        for face in faces:
            a = centroid_points([vertex_xyz[vertex] for vertex in self.mesh.face_vertices(face)])
            n = self.mesh.face_normal(face)
            b = add_vectors(a, scale_vector(n, scale))
            lines.append({
                'start': a,
                'end': b,
                'name': "{}.facenormal.{}".format(self.mesh.name, face),
                'color': color,
                'arrow': 'end'})
        return compas_rhino.draw_lines(lines, layer=self.layer, clear=False, redraw=False)
Beispiel #8
0
    def get_vector_on_face_faces(self, point, f_key, name, vec=[0, 0, 0]):
        pt_cloud = []

        f_keys = [f_key]
        f_keys.extend(self.c_mesh.face_neighbors(f_key))
        f_keys = list(set(f_keys))

        f_vectors_a = self.c_mesh.faces_attribute(f_keys,
                                                      str(name) + '_a'
                                                      )
        f_vectors_b = self.c_mesh.faces_attribute(f_keys,
                                                      str(name) + '_b',
                                                      )
        f_vectors = ut.filter_aligned_vectors(vec, f_vectors_a, f_vectors_b)

        for f_key in f_keys:
            pt_cloud.append(self.c_mesh.face_centroid(f_key))

        weights = ut.get_dist_weights(point, pt_cloud)
        new_vectors = []
        for idx, vec in enumerate(f_vectors):
            new_vector = cg.scale_vector(vec, weights[idx])
            new_vectors.append(new_vector)

        return reduce(lambda x, y: cg.add_vectors(x, y), new_vectors)
Beispiel #9
0
def matrix_from_orthogonal_projection(plane):
    """Returns an orthogonal projection matrix to project onto a plane.

    Parameters
    ----------
    plane : [point, normal] | :class:`compas.geometry.Plane`
        The plane to project onto.

    Returns
    -------
    list[list[float]]
        The 4x4 transformation matrix representing an orthogonal projection.

    Examples
    --------
    >>> point = [0, 0, 0]
    >>> normal = [0, 0, 1]
    >>> plane = (point, normal)
    >>> P = matrix_from_orthogonal_projection(plane)

    """
    point, normal = plane
    T = identity_matrix(4)
    normal = normalize_vector(normal)

    for j in range(3):
        for i in range(3):
            T[i][j] -= normal[i] * normal[j]  # outer_product

    T[0][3], T[1][3], T[2][3] = scale_vector(normal,
                                             dot_vectors(point, normal))
    return T
Beispiel #10
0
def random_vector():
    return scale_vector(
        normalize_vector([
            random.choice([-1, +1]) * random.random(),
            random.choice([-1, +1]) * random.random(),
            random.choice([-1, +1]) * random.random(),
        ]), random.random())
def create_overhang_texture(slicer, overhang_distance):
    """Creates a cool overhang texture"""

    print("Creating cool texture")

    for i, layer in enumerate(slicer.layers):
        if i % 10 == 0 and i > 0:
            # for every 10th layer, except for the brim
            # print(layer)
            for j, path in enumerate(layer.paths):
                # print(path)
                # create an empty layer in which we can store our modified points
                new_path = []
                for k, pt in enumerate(path.points):
                    # for every second point (only even points)
                    if k % 2 == 0:
                        # get the normal of the point in relation to the mesh
                        normal = get_normal_of_path_on_xy_plane(k,
                                                                pt,
                                                                path,
                                                                mesh=None)
                        # scale the vector by a number to move the point
                        normal_scaled = scale_vector(normal,
                                                     -overhang_distance)
                        # create a new point by adding the point and the normal vector
                        new_pt = add_vectors(pt, normal_scaled)
                        # recreate the new_pt values as compas_points
                        pt = Point(new_pt[0], new_pt[1], new_pt[2])

                    # append the points to the new path
                    new_path.append(pt)

                # replace the current path with the new path that we just created
                layer.paths[j] = Path(new_path, is_closed=path.is_closed)
Beispiel #12
0
def smooth_network_length(network, lmin, lmax, fixed=None, kmax=1, d=0.5, callback=None, callback_args=None):
    fixed = fixed or []
    fixed = set(fixed)

    if callback:
        if not callable(callback):
            raise Exception('The callback is not callable.')

    for k in range(kmax):
        key_xyz = {key: network.vertex_coordinates(key) for key in network.vertices()}

        for key in network:
            if key in fixed:
                continue

            ep = key_xyz[key]
            points = []

            for nbr in network.vertex_neighbours(key):
                sp    = key_xyz[nbr]
                vec   = subtract_vectors(ep, sp)
                lvec  = length_vector(vec)
                scale = max(lmin, min(lvec, lmax))
                p     = add_vectors(sp, scale_vector(vec, scale / lvec))
                points.append(p)

            x, y, z = centroid_points(points)

            attr = network.vertex[key]
            attr['x'] += d * (x - ep[0])
            attr['y'] += d * (y - ep[1])
            attr['z'] += d * (z - ep[2])

        if callback:
            callback(network, k, callback_args)
Beispiel #13
0
def test_remeshing():

    FILE = os.path.join(HERE, '../..', 'data', 'Bunny.ply')

    # ==============================================================================
    # Get the bunny and construct a mesh
    # ==============================================================================

    bunny = TriMesh.from_ply(FILE)

    bunny.cull_vertices()

    # ==============================================================================
    # Move the bunny to the origin and rotate it upright.
    # ==============================================================================

    vector = scale_vector(bunny.centroid, -1)

    T = Translation.from_vector(vector)
    S = Scale.from_factors([100, 100, 100])
    R = Rotation.from_axis_and_angle(Vector(1, 0, 0), math.radians(90))

    bunny.transform(R * S * T)

    # ==============================================================================
    # Remesh
    # ==============================================================================

    length = bunny.average_edge_length

    bunny.remesh(4 * length)

    bunny.to_mesh()
Beispiel #14
0
def mesh_offset(
    mesh,
    distance=1.0,
):
    """Offset a mesh.

    Parameters
    ----------
    mesh : Mesh
        A Mesh to offset.
    distance : float
        The offset distance.

    Returns
    -------
    Mesh
        The offset mesh.

    """
    offset = mesh.copy()

    for key in offset.vertices():
        normal = mesh.vertex_normal(key)
        xyz = mesh.vertex_coordinates(key)
        offset.vertex_attributes(
            key, 'xyz', add_vectors(xyz, scale_vector(normal, distance)))

    return offset
Beispiel #15
0
    def draw_vectors(self, points, vectors, scale):
        rs_lines = []
        for idx, point in enumerate(points):
            vector_a, vector_b = vectors[idx]

            vector_a = cg.scale_vector(vector_a, scale)
            vector_b = cg.scale_vector(vector_b, scale)

            pt_a = cg.add_vectors(point, vector_a)
            pt_b = cg.add_vectors(point, vector_b)

            line = rs.AddLine(
                rs.AddPoint(pt_a),  # rs
                rs.AddPoint(pt_b))
            rs_lines.append(line)  # rs
        return rs_lines
Beispiel #16
0
 def draw_vertexnormals(self, keys=None, color=None, scale=None):
     keys = keys or list(self.mesh.vertices())
     scale = scale or self.settings.get('scale.normal:vertex')
     color = color or self.settings.get('color.normal:vertex')
     lines = []
     for key in keys:
         a = self.mesh.vertex_coordinates(key)
         n = self.mesh.vertex_normal(key)
         b = add_vectors(a, scale_vector(n, scale))
         lines.append({
             'start':
             a,
             'end':
             b,
             'color':
             color,
             'name':
             "{}.vertex.normal.{}".format(self.mesh.name, key),
             'arrow':
             'end'
         })
     return compas_rhino.draw_lines(lines,
                                    layer=self.layer,
                                    clear=False,
                                    redraw=False)
Beispiel #17
0
def line_point(line, t=.5):
    """Point on a lyline at a normalised parameter.

	Parameters
	----------
	polyline: list
	    The XYZ coordinates of the extremities of the line.
	t: float 
	    The normalised parameter of the point on the polyline between 0 and 1.

	Returns
	-------
	xyz: list, None
		The point coordinates.
		None if the parameter is not in [0,1]

	Raises
	------
	-

	"""

    u, v = line
    uv = subtract_vectors(v, u)
    return add_vectors(u, scale_vector(uv, t))
Beispiel #18
0
    def get_vector_on_face_ext(self, point, f_key, name, vec=[0, 0, 0]):
        f_keys = [f_key]
        f_keys.extend(self.c_mesh.face_neighbours(f_key))
        v_keys = []
        pt_cloud = []

        for f_key in f_keys:
            v_keys.extend(self.c_mesh.face_vertices(f_key))

        v_keys = list(set(v_keys))
        v_vectors_a = self.c_mesh.vertices_attribute(name=str(name) + '_a',
                                                        keys=v_keys
                                                        )
        v_vectors_b = self.c_mesh.vertices_attribute(name=str(name) + '_b',
                                                        keys=v_keys
                                                        )

        v_vectors = ut.filter_aligned_vectors(vec, v_vectors_a, v_vectors_b)

        for v_key in v_keys:
            pt_cloud.append(self.c_mesh.vertex_coordinates(v_key))

        weights = ut.get_dist_weights(point, pt_cloud)
        new_vectors = []
        for idx, vec in enumerate(v_vectors):
            new_vector = cg.scale_vector(vec, weights[idx])
            new_vectors.append(new_vector)

        return reduce(lambda x, y: cg.add_vectors(x, y), new_vectors)
Beispiel #19
0
def matrix_from_parallel_projection(point, normal, direction):
    """Returns an parallel projection matrix to project onto a plane defined by
    point, normal and direction.

    Parameters
    ----------
    point : list of float
        Base point of the plane.
    normal : list of float
        Normal vector of the plane.
    direction : list of float
        Direction of the projection.

    Examples
    --------
    >>> point = [0, 0, 0]
    >>> normal = [0, 0, 1]
    >>> direction = [1, 1, 1]
    >>> P = matrix_from_parallel_projection(point, normal, direction)

    """
    T = identity_matrix(4)
    normal = normalize_vector(normal)

    scale = dot_vectors(direction, normal)
    for j in range(3):
        for i in range(3):
            T[i][j] -= direction[i] * normal[j] / scale

    T[0][3], T[1][3], T[2][3] = scale_vector(
        direction,
        dot_vectors(point, normal) / scale)
    return T
Beispiel #20
0
    def draw_vertexnormals(self, vertices=None, color=(0, 255, 0), scale=1.0):
        """Draw the normals at the vertices of the mesh.

        Parameters
        ----------
        vertices : list, optional
            A selection of vertex normals to draw.
            Default is to draw all vertex normals.
        color : tuple, optional
            The color specification of the normal vectors.
            The default color is green, ``(0, 255, 0)``.
        scale : float, optional
            Scale factor for the vertex normals.
            Default is ``1.0``.

        Returns
        -------
        list
            The GUIDs of the created Rhino objects.

        """
        vertex_xyz = self.vertex_xyz
        vertices = vertices or list(self.mesh.vertices())
        lines = []
        for vertex in vertices:
            a = vertex_xyz[vertex]
            n = self.mesh.vertex_normal(vertex)
            b = add_vectors(a, scale_vector(n, scale))
            lines.append({
                'start': a,
                'end': b,
                'color': color,
                'name': "{}.vertexnormal.{}".format(self.mesh.name, vertex),
                'arrow': 'end'})
        return compas_rhino.draw_lines(lines, layer=self.layer, clear=False, redraw=False)
Beispiel #21
0
def matrix_from_orthogonal_projection(point, normal):
    """Returns an orthogonal projection matrix to project onto a plane defined
    by point and normal.

    Parameters
    ----------
    point : list of float
        Base point of the plane.
    normal : list of float
        Normal vector of the plane.

    Examples
    --------
    >>> point = [0, 0, 0]
    >>> normal = [0, 0, 1]
    >>> P = matrix_from_orthogonal_projection(point, normal)

    """
    T = identity_matrix(4)
    normal = normalize_vector(normal)

    for j in range(3):
        for i in range(3):
            T[i][j] -= normal[i] * normal[j]  # outer_product

    T[0][3], T[1][3], T[2][3] = scale_vector(normal,
                                             dot_vectors(point, normal))
    return T
Beispiel #22
0
def tween_points_distance(points1, points2, dist, index=None):
    """Compute an interpolated set of points between two sets of points, at
    a given distance.

    Parameters
    ----------
    points1 : list[[float, float, float] | :class:`compas.geometry.Point`]
        The first set of points.
    points2 : list[[float, float, float] | :class:`compas.geometry.Point`]
        The second set of points.
    dist : float
        The distance from the first set to the second at which to compute the interpolated set.
    index: int, optional
        The index of the point in the first set from which to calculate the distance to the second set.
        If no value is given, the first point will be used.

    Returns
    -------
    list[list[[float, float, float]]]
        List of points.

    """
    if not index:
        index = 0
    d = distance_point_point(points1[index], points2[index])
    scale = float(dist) / d
    tweens = []
    for i in range(len(points1)):
        tweens.append(
            add_vectors(
                points1[i],
                scale_vector(subtract_vectors(points2[i], points1[i]), scale)))
    return tweens
def closest_point_on_line(a, b, c):
    """Closest point on line.
    Same as projection.

    Parameters
    ----------
    a: list
        First line point coordinates.
    b: list
        Second line point coordinates.
    c: list
        Point coordinates.

    Returns
    -------
    tuple
        The projected point coordinates and the distance from the input point.
    """

    ab = subtract_vectors(b, a)
    ac = subtract_vectors(c, a)

    if length_vector(ab) == 0:
        return a, distance_point_point(c, a)

    p = add_vectors(
        a, scale_vector(ab,
                        dot_vectors(ab, ac) / length_vector(ab)**2))
    distance = distance_point_point(c, p)
    return p, distance
Beispiel #24
0
def tween_points(points1, points2, num):
    """Compute the interpolated points between two sets of points.

    Parameters
    ----------
    points1 : list
        The first set of points
    points2 : list
        The second set of points
    num : int
        The number of interpolated sets to return

    Returns
    -------
    list
        Nested list of points.

    Raises
    ------
    AssertionError
        When the two point sets do not have the same length.

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

        from compas.geometry import tween_points
        from compas_plotters import Plotter

        points1 = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [2.0, 0.0, 0.0], [3.0, 0.0, 0.0]]
        points2 = [[0.0, 0.0, 0.0], [1.0, 3.0, 0.0], [2.0, 1.0, 0.0], [3.0, 0.0, 0.0]]

        tweens = tween_points(points1, points2, 5)

        polylines = [{'points': points1, 'width': 1.0}]

        for points in tweens:
            polylines.append({'points': points, 'width': 0.5})

        polylines.append({'points': points2, 'width': 1.0})

        plotter = Plotter()
        plotter.draw_polylines(polylines)
        plotter.show()

    Notes
    -----
    The two point sets should have the same length.

    """
    vectors = [vector_from_points(p1, p2) for p1, p2 in zip(points1, points2)]
    tweens = []
    for j in range(num):
        tween = []
        for point, vector in zip(points1, vectors):
            scale = (j + 1.0) / (num + 1.0)
            tween.append(add_vectors(point, scale_vector(vector, scale)))
        tweens.append(tween)
    return tweens
Beispiel #25
0
def matrix_from_parallel_projection(plane, direction):
    """Returns an parallel projection matrix to project onto a plane.

    Parameters
    ----------
    plane : compas.geometry.Plane or (point, normal)
        The plane to project onto.
    direction : list of float
        Direction of the projection.

    Examples
    --------
    >>> point = [0, 0, 0]
    >>> normal = [0, 0, 1]
    >>> plane = (point, normal)
    >>> direction = [1, 1, 1]
    >>> P = matrix_from_parallel_projection(plane, direction)

    """
    point, normal = plane
    T = identity_matrix(4)
    normal = normalize_vector(normal)

    scale = dot_vectors(direction, normal)
    for j in range(3):
        for i in range(3):
            T[i][j] -= direction[i] * normal[j] / scale

    T[0][3], T[1][3], T[2][3] = scale_vector(
        direction,
        dot_vectors(point, normal) / scale)
    return T
Beispiel #26
0
def mesh_offset(mesh, offset=1.0, cls=None):
    """Offset a mesh.

    Parameters
    ----------
    mesh : Mesh
        A Mesh to offset.
    offset : real
        The offset distance.

    Returns
    -------
    Mesh
        The offset mesh.

    """
    if cls is None:
        cls = type(mesh)

    # new coordinates of vertex keys
    vertex_map = {}
    for i, vkey in enumerate(mesh.vertices()):
        if len(mesh.vertex_neighbors(vkey)) == 0:
            vertex_map[vkey] = i, [0, 0, 0]
        else:
            vertex_map[vkey] = i, add_vectors(
                mesh.vertex_coordinates(vkey),
                scale_vector(mesh.vertex_normal(vkey), offset))

    vertices = [xyz for i, xyz in vertex_map.values()]
    faces = [[vertex_map[vkey][0] for vkey in mesh.face_vertices(fkey)]
             for fkey in mesh.faces()]

    return cls.from_vertices_and_faces(vertices, faces)
Beispiel #27
0
def polygon_area_footprint(polygon):
    """Compute the non-oriented area of a polygon (can be convex or concave).

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

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

    """
    area = 0
    w    = centroid_points(polygon)

    for i in range(-1, len(polygon) - 1):
        u      = polygon[i]
        v      = polygon[i + 1]
        uv     = subtract_vectors(v, u)
        vw     = subtract_vectors(w, v)
        normal = scale_vector(cross_vectors(uv, vw), 0.5)
        area   += length_vector(normal)

    return area
Beispiel #28
0
    def draw_facenormals(self, color=None, scale=1.0):
        """Draw the normals of the faces.

        Parameters
        ----------
        color : str (HEX) or tuple (RGB), optional
            The color specification of the normal vectors.
            String values are interpreted as hex colors (e.g. ``'#ff0000'`` for red).
            Tuples are interpreted as RGB component specifications (e.g. ``(255, 0, 0) for red``.
            The default value is ``None``, in which case the labels are assigned
            the default normal vector color (``self.defaults['color.normal']``).

        Notes
        -----
        The face normals are named using the following template:
        ``"{}.face.normal.{}".format(self.datastructure.name, key)``.
        This name is used afterwards to identify the normals in the Rhino model.

        """
        color = color or self.defaults.get('color.normal')

        lines = []
        for fkey, attr in self.datastructure.faces(True):
            n = self.datastructure.face_normal(fkey)
            sp = self.datastructure.face_centroid(fkey)
            ep = add_vectors(sp, scale_vector(n, scale))
            lines.append({
                'start': sp,
                'end': ep,
                'name': "{}.face.normal.{}".format(self.datastructure.name, fkey),
                'color': color,
                'arrow': 'end'
            })
        return compas_rhino.draw_lines(lines, layer=self.layer, clear=False, redraw=False)
Beispiel #29
0
def calc_correction_vector_tip(pt_new, base_pts):
    """Computing correction vector to meet the distance threshold.
        return vector P-P_c (figure below).

    .. image:: ../images/vertex_correction_to_top_connection.png
        :scale: 80 %
        :align: center

    Parameters
    ----------
    pt_new : [type]
        [description]
    base_pts : list of three points
        contact base points for the base bars
    """
    assert len(base_pts) == 3
    vec_x   = normalize_vector(vector_from_points(base_pts[0], base_pts[1]))
    vec_y   = normalize_vector(vector_from_points(base_pts[0], base_pts[2]))
    vec_z   = normalize_vector(cross_vectors(vec_x, vec_y))
    pl_test = (base_pts[0], vec_z)
    dist_p  = distance_point_plane(pt_new, pl_test)
    pt_proj = project_point_plane(pt_new, pl_test)

    if dist_p < NODE_CORRECTION_TOP_DISTANCE:
        vec_m = scale_vector(normalize_vector(vector_from_points(pt_proj, pt_new)), NODE_CORRECTION_TOP_DISTANCE)
        pt_n = add_vectors(pt_proj, vec_m)
    else:
        pt_n = None
    return pt_n
def beam_plane(beam):
    p1 = SHELL.vertex_coordinates(beam[1])
    p0 = SHELL.vertex_coordinates(beam[0])
    xaxis = subtract_vectors(p1, p0)
    yaxis = cross_vectors(ZAXIS, xaxis)
    normal = normalize_vector(yaxis)
    origin = add_vectors(p0, scale_vector(normal, OFFSET))
    return origin, normal