Exemple #1
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
Exemple #2
0
    def board_setup(self):
        for my_layer in range(layer_no):
            if my_layer % 2 == 0:
                my_frame = self.origin_fr
                my_grid = self.ceiling_grids[0]
            else:
                my_frame = self.sec_fr
                my_grid = self.ceiling_grids[1][0]
            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
            board_code = 0
            for i, dist in enumerate(my_grid):
                my_board = self.timberboards[my_layer][board_code]
                # for the inner parts
                if self.skipping and 0 < my_layer < self.layer_no - 1 and my_layer%2 == 0 and \
                    0 < i < len(my_grid) - 1 and i%2 != 0:
                    continue
                # build the three vectors with which we later find he centre point
                my_vec1 = scale_vector(my_dir1, my_board.length / 2)
                my_vec2 = scale_vector(my_dir2, dist)
                my_vec3 = Vector(0, 0, my_board.z_drop - 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)
                my_board.length_vector = normalize_vector(my_vec1)
                my_board.width_vector = normalize_vector(my_vec2)
                my_board.box_update()
                board_code += 1
Exemple #3
0
def find_points_extreme(pts_all, pts_init):
    """update a bar's axis end point based on all the contact projected points specified in `pts_all`

    Parameters
    ----------
    pts_all : list of points
        all the contact points projected on the axis (specified by pts_init)
    pts_init : list of two points
        the initial axis end points

    Returns
    -------
    [type]
        [description]
    """
    vec_init = normalize_vector(vector_from_points(*pts_init))
    # * find the pair of points with maximal distance
    sorted_pt_pairs = sorted(combinations(pts_all, 2), key=lambda pt_pair: distance_point_point(*pt_pair))
    pts_draw = sorted_pt_pairs[-1]

    vec_new = normalize_vector(vector_from_points(*pts_draw))
    if angle_vectors(vec_init, vec_new, deg=True) > 90:
        # angle can only be 0 or 180
        pts_draw = pts_draw[::-1]

    # ext_len = 30
    # pts_draw = (add_vectors(pts_draw[0], scale_vector(normalize_vector(vector_from_points(pts_draw[1], pts_draw[0])), ext_len)), add_vectors(pts_draw[1], scale_vector(normalize_vector(vector_from_points(pts_draw[0], pts_draw[1])), ext_len)))

    return pts_draw
def set_wait_time_on_sharp_corners(print_organizer, threshold=0.5 * math.pi, wait_time=0.3):
    """
    Sets a wait time at the sharp corners of the path, based on the angle threshold.

    Parameters
    ----------
    print_organizer: :class:`compas_slicer.print_organization.BasePrintOrganizer`
    threshold: float
        angle_threshold
    wait_time: float
        Time in seconds to introduce to add as a wait time
    """
    number_of_wait_points = 0
    for printpoint, i, j, k in print_organizer.printpoints_indices_iterator():
        neighbors = print_organizer.get_printpoint_neighboring_items('layer_%d' % i, 'path_%d' % j, k)
        prev_ppt = neighbors[0]
        next_ppt = neighbors[1]

        if prev_ppt and next_ppt:
            v_to_prev = normalize_vector(Vector.from_start_end(printpoint.pt, prev_ppt.pt))
            v_to_next = normalize_vector(Vector.from_start_end(printpoint.pt, next_ppt.pt))
            a = abs(Vector(*v_to_prev).angle(v_to_next))

            if a < threshold:
                printpoint.wait_time = wait_time
                printpoint.blend_radius = 0.0  # 0.0 blend radius for points where the robot will wait
                number_of_wait_points += 1
    logger.info('Added wait times for %d points' % number_of_wait_points)
Exemple #5
0
    def from_basis_vectors(cls, xaxis, yaxis):
        """Creates a ``Rotation`` from basis vectors (= orthonormal vectors).

        Parameters
        ----------
        xaxis : compas.geometry.Vector or list
            The x-axis of the frame.
        yaxis : compas.geometry.Vector or list
            The y-axis of the frame.

        Examples
        --------
        >>> xaxis = [0.68, 0.68, 0.27]
        >>> yaxis = [-0.67, 0.73, -0.15]
        >>> R = Rotation.from_basis_vectors(xaxis, yaxis)
        """
        xaxis = normalize_vector(list(xaxis))
        yaxis = normalize_vector(list(yaxis))
        zaxis = cross_vectors(xaxis, yaxis)
        yaxis = cross_vectors(zaxis, xaxis)
        matrix = [[xaxis[0], yaxis[0], zaxis[0], 0],
                  [xaxis[1], yaxis[1], zaxis[1], 0],
                  [xaxis[2], yaxis[2], zaxis[2], 0], [0, 0, 0, 1]]
        R = cls()
        R.matrix = matrix
        return R
Exemple #6
0
def orthonormalize_axes(xaxis, yaxis):
    """Corrects xaxis and yaxis to be unit vectors and orthonormal.

    Parameters
    ----------
    xaxis: :class:`Vector` or list of float
    yaxis: :class:`Vector` or list of float

    Returns
    -------
    tuple: (xaxis, yaxis)
        The corrected axes.

    Raises
    ------
    ValueError: If xaxis and yaxis cannot span a plane.

    Examples
    --------
    >>> xaxis = [1, 4, 5]
    >>> yaxis = [1, 0, -2]
    >>> xaxis, yaxis = orthonormalize_axes(xaxis, yaxis)
    >>> allclose(xaxis, [0.1543, 0.6172, 0.7715], tol=0.001)
    True
    >>> allclose(yaxis, [0.6929, 0.4891, -0.5298], tol=0.001)
    True
    """
    xaxis = normalize_vector(xaxis)
    yaxis = normalize_vector(yaxis)
    zaxis = cross_vectors(xaxis, yaxis)
    if not norm_vector(zaxis):
        raise ValueError("Xaxis and yaxis cannot span a plane.")
    yaxis = cross_vectors(normalize_vector(zaxis), xaxis)
    return xaxis, yaxis
def match_paths_orientations(pts, reference_points, is_closed):
    """
    Check if new curve has same direction as prev curve, otherwise reverse.

    Parameters
    ----------
    pts: list, :class: 'compas.geometry.Point'. The list of points whose direction we are fixing.
    reference_points: list, :class: 'compas.geometry.Point'. [p1, p2] Two reference points.
    is_closed : bool, Determines if the path is closed or open
    """
    if len(pts) > 2 and len(reference_points) > 2:
        v1 = normalize_vector(subtract_vectors(pts[0], pts[2]))
        v2 = normalize_vector(
            subtract_vectors(reference_points[0], reference_points[2]))
    else:
        v1 = normalize_vector(subtract_vectors(pts[0], pts[1]))
        v2 = normalize_vector(
            subtract_vectors(reference_points[0], reference_points[1]))

    if dot_vectors(v1, v2) < 0:
        if is_closed:
            items = deque(reversed(pts))
            items.rotate(1)  # bring last point again in the front
            pts = list(items)
        else:
            pts.reverse()
    return pts
    def board_geometry_setup(self):
        for my_layer in range(layer_no):
            if my_layer % 2 == 0:
                my_frame = self.origin_fr
                my_grid = self.ceiling_grids[0][0]
            else:
                my_frame = self.sec_fr
                my_grid = self.ceiling_grids[1][0]
            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
            board_code = 0
            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
                if my_board.location == "high":
                    my_vec1 = scale_vector(my_dir1, primary_length - my_board.length / 2)
                # all other cases
                else:
                    my_vec1 = scale_vector(my_dir1, my_board.length / 2)

                my_vec2 = scale_vector(my_dir2, dist)
                my_vec3 = Vector(0, 0, my_board.z_drop - 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)
                my_board.length_vector = normalize_vector(my_vec1)
                my_board.width_vector = normalize_vector(my_vec2)
                my_board.box_update()
                board_code += 1
Exemple #9
0
def draw_circle(circle, color=None, n=100):
    (center, normal), radius = circle
    cx, cy, cz = center
    a, b, c = normal

    u = -1.0, 0.0, a
    v = 0.0, -1.0, b
    w = cross_vectors(u, v)

    uvw = [normalize_vector(u), normalize_vector(v), normalize_vector(w)]

    color = color if color else (1.0, 0.0, 0.0, 0.5)
    sector = 2 * pi  / n

    glColor4f(*color)

    glBegin(GL_POLYGON)
    for i in range(n):
        a = i * sector
        x = radius * cos(a)
        y = radius * sin(a)
        z = 0
        x, y, z = global_coords_numpy(center, uvw, [[x, y, z]]).tolist()[0]
        glVertex3f(x, y, z)
    glEnd()

    glBegin(GL_POLYGON)
    for i in range(n):
        a = -i * sector
        x = radius * cos(a)
        y = radius * sin(a)
        z = 0
        x, y, z = global_coords_numpy(center, uvw, [[x, y, z]]).tolist()[0]
        glVertex3f(x, y, z)
    glEnd()
Exemple #10
0
def matrix_from_basis_vectors(xaxis, yaxis):
    """Creates a rotation matrix from basis vectors (= orthonormal vectors).

    Parameters
    ----------
    xaxis : list of float
        The x-axis of the frame.
    yaxis : list of float
        The y-axis of the frame.

    Examples
    --------
    >>> xaxis = [0.68, 0.68, 0.27]
    >>> yaxis = [-0.67, 0.73, -0.15]
    >>> R = matrix_from_basis_vectors(xaxis, yaxis)

    """
    xaxis = normalize_vector(list(xaxis))
    yaxis = normalize_vector(list(yaxis))
    zaxis = cross_vectors(xaxis, yaxis)
    yaxis = cross_vectors(zaxis, xaxis)  # correction

    R = identity_matrix(4)
    R[0][0], R[1][0], R[2][0] = xaxis
    R[0][1], R[1][1], R[2][1] = yaxis
    R[0][2], R[1][2], R[2][2] = zaxis
    return R
Exemple #11
0
    def from_basis_vectors(cls, xaxis, yaxis):
        """Construct a rotation transformation from basis vectors (= orthonormal vectors).

        Parameters
        ----------
        xaxis : [float, float, float] | :class:`compas.geometry.Vector`
            The x-axis of the frame.
        yaxis : [float, float, float] | :class:`compas.geometry.Vector`
            The y-axis of the frame.

        Returns
        -------
        :class:`compas.geometry.Rotation`

        Examples
        --------
        >>> xaxis = [0.68, 0.68, 0.27]
        >>> yaxis = [-0.67, 0.73, -0.15]
        >>> R = Rotation.from_basis_vectors(xaxis, yaxis)

        """
        xaxis = normalize_vector(list(xaxis))
        yaxis = normalize_vector(list(yaxis))
        zaxis = cross_vectors(xaxis, yaxis)
        yaxis = cross_vectors(zaxis, xaxis)
        matrix = [[xaxis[0], yaxis[0], zaxis[0], 0],
                  [xaxis[1], yaxis[1], zaxis[1], 0],
                  [xaxis[2], yaxis[2], zaxis[2], 0], [0, 0, 0, 1]]
        R = cls()
        R.matrix = matrix
        return R
Exemple #12
0
    def from_basis_vectors(cls, xaxis, yaxis):
        """Creates a ``Rotation`` from basis vectors (= orthonormal vectors).

        Parameters
        ----------
        xaxis : :class:`Vector`
            The x-axis of the frame.
        yaxis : :class:`Vector`
            The y-axis of the frame.

        Examples
        --------
        >>> xaxis = [0.68, 0.68, 0.27]
        >>> yaxis = [-0.67, 0.73, -0.15]
        >>> R = Rotation.from_basis_vectors(xaxis, yaxis)
        """
        xaxis = normalize_vector(list(xaxis))
        yaxis = normalize_vector(list(yaxis))
        zaxis = cross_vectors(xaxis, yaxis)
        yaxis = cross_vectors(zaxis, xaxis)  # correction

        R = cls()
        R.matrix[0][0], R.matrix[1][0], R.matrix[2][0] = xaxis
        R.matrix[0][1], R.matrix[1][1], R.matrix[2][1] = yaxis
        R.matrix[0][2], R.matrix[1][2], R.matrix[2][2] = zaxis
        return R
Exemple #13
0
    def separate(self, dst, boids, mxf=0.02, mxs=0.02):
        count = 0
        sum_vec = [0, 0, 0]
        tol = 1e-6

        for boid in boids:
            d = cg.distance_point_point(self.pos, boid.pos)
            print('distance is {}'.format(d))

            if d > tol and d < dst:
                dif = subtract_vectors(self.pos, boid.pos)
                dif = cg.normalize_vector(cg.scale_vector(dif, 1/d))
                sum_vec = cg.add_vectors(dif, sum_vec)
                count += 1

            if count > 0:
                sum_vec = cg.normalize_vector(cg.scale_vector(sum_vec,
                                                              1/count)
                                              )
                sum_vec = cg.scale_vector(sum_vec, mxs)

                # Reynold's steering formula
                steer = subtract_vectors(sum_vec, self.vel)
                steer = ut.limit_vector(steer, mxf)
                return steer
        return sum_vec
Exemple #14
0
 def _cross_edges(edge1, edge2):
     a, b      = edge1
     c, d      = edge2
     edge1_vec = normalize_vector(subtract_vectors(b, a))
     edge2_vec = normalize_vector(subtract_vectors(d, c))
     cross     = cross_vectors(edge1_vec, edge2_vec)
     return cross
Exemple #15
0
def calc_correction_vector(b_struct, pt_new, bar_pair):
    """Computing correction vector to meet the angle threshold.
        return vector P-P_c (figure below).

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

    Parameters
    ----------
    b_struct : [type]
        [description]
    pt_new : [type]
        [description]
    bar_pair : list of two int
        BarS vertex key, representing two bars

    Returns
    -------
    list of two points
        return None if feasible (bigger than the angle threshold), otherwise return the line connecting pt_int and modified pt
    """
    bar1  = b_struct.vertex[bar_pair[0]]
    bar2  = b_struct.vertex[bar_pair[1]]
    pt_int = intersection_bars_base(b_struct, bar_pair)

    vec_x   = normalize_vector(vector_from_points(bar1["axis_endpoints"][0], bar1["axis_endpoints"][1]))
    vec_y   = normalize_vector(vector_from_points(bar2["axis_endpoints"][0], bar2["axis_endpoints"][1]))
    # contact vector
    vec_z   = normalize_vector(cross_vectors(vec_x, vec_y))
    # test plane
    pl_test = (pt_int, vec_z)
    vec_m   = correct_angle(pt_new, pt_int, pl_test)
    return vec_m
Exemple #16
0
def matrix_from_shear(angle, direction, point, normal):
    """Constructs a shear matrix by an angle along the direction vector on the
    shear plane (defined by point and normal).

    Parameters
    ----------
    angle : float
        The angle in radians.
    direction : list of float
        The direction vector as list of 3 numbers.
        It must be orthogonal to the normal vector.
    point : list of float
        The point of the shear plane as list of 3 numbers.
    normal : list of float
        The normal of the shear plane as list of 3 numbers.

    Raises
    ------
    ValueError
        If direction and normal are not orthogonal.

    Notes
    -----
    A point P is transformed by the shear matrix into P" such that
    the vector P-P" is parallel to the direction vector and its extent is
    given by the angle of P-P'-P", where P' is the orthogonal projection
    of P onto the shear plane (defined by point and normal).

    Examples
    --------
    >>> angle = 0.1
    >>> direction = [0.1, 0.2, 0.3]
    >>> point = [4, 3, 1]
    >>> normal = cross_vectors(direction, [1, 0.3, -0.1])
    >>> S = matrix_from_shear(angle, direction, point, normal)

    """
    fabs = math.fabs

    normal = normalize_vector(normal)
    direction = normalize_vector(direction)

    if fabs(dot_vectors(normal, direction)) > _EPS:
        raise ValueError('Direction and normal vectors are not orthogonal')

    angle = math.tan(angle)
    M = identity_matrix(4)

    for j in range(3):
        for i in range(3):
            M[i][j] += angle * direction[i] * normal[j]

    M[0][3], M[1][3], M[2][3] = scale_vector(
        direction, -angle * dot_vectors(point, normal))

    return M
def transformed_stress_vector_fields(mesh, vector_fields, stress_type,
                                     ref_vector):
    """
    Rescales a vector field based on a plane stress transformation.
    """
    vf1, vf2 = vector_fields

    # TODO: mapping is not robust! depends on naming convention
    stress_components = {
        "bending": {
            "names": ["mx", "my", "mxy"],
            "ps": "m_1"
        },
        "axial": {
            "names": ["nx", "ny", "nxy"],
            "ps": "n_1"
        }
    }

    stress_names = stress_components[stress_type]["names"]
    vf_ps = mesh.vector_field(stress_components[stress_type]["ps"])

    vf1_transf = VectorField()
    vf2_transf = VectorField()

    for fkey in mesh.faces():
        # query stress components
        sx, sy, sxy = mesh.face_attributes(fkey, names=stress_names)

        # generate principal stresses and angles
        s1a, s1 = principal_stresses_and_angles(sx, sy, sxy)
        s1, angle1 = s1a

        vector_ps = vf_ps[fkey]
        vector1 = vf1[fkey]
        vector2 = vf2[fkey]

        # compute delta between reference vector and principal bending vector
        # TODO: will take m1 as reference. does this always hold?

        delta = angle1 - angle_vectors(vector_ps, ref_vector)
        # add delta to angles of the vector field to transform
        theta = delta + angle_vectors(vector1, ref_vector)

        # transform stresses - this becomes the scale of the vectors
        s1, s2, _ = transformed_stresses(sx, sy, sxy, theta)

        vf1_transf.add_vector(fkey, scale_vector(normalize_vector(vector1),
                                                 s1))
        vf2_transf.add_vector(fkey, scale_vector(normalize_vector(vector2),
                                                 s2))

    return vf1_transf, vf2_transf
    def from_basis_vectors(cls, xaxis, yaxis):
        """Create rotation matrix from basis vectors (= orthonormal vectors).
        """
        xaxis = normalize_vector(list(xaxis))
        yaxis = normalize_vector(list(yaxis))
        zaxis = cross_vectors(xaxis, yaxis)
        yaxis = cross_vectors(zaxis, xaxis) # slight correction

        rotation = cls()
        rotation.matrix[0][0], rotation.matrix[1][0], rotation.matrix[2][0] = xaxis
        rotation.matrix[0][1], rotation.matrix[1][1], rotation.matrix[2][1] = yaxis
        rotation.matrix[0][2], rotation.matrix[1][2], rotation.matrix[2][2] = zaxis
        return rotation
Exemple #19
0
def get_normal_of_path_on_xy_plane(k, point, path, mesh):
    """
    Finds the normal of the curve that lies on the xy plane at the point with index k

    Parameters
    ----------
    k: int, index of the point
    point: :class: 'compas.geometry.Point'
    path: :class: 'compas_slicer.geometry.Path'
    mesh: :class: 'compas.datastructures.Mesh'

    Returns
    ----------
    :class: 'compas.geometry.Vector'
    """

    # find mesh normal is not really needed in the 2D case of planar slicer
    # instead we only need the normal of the curve based on the neighboring pts
    if (0 < k < len(path.points) - 1) or path.is_closed:
        prev_pt = path.points[k - 1]
        next_pt = path.points[(k + 1) % len(path.points)]
        v1 = np.array(normalize_vector(Vector.from_start_end(prev_pt, point)))
        v2 = np.array(normalize_vector(Vector.from_start_end(point, next_pt)))
        v = (v1 + v2) * 0.5
        normal = [-v[1], v[0],
                  v[2]]  # rotate 90 degrees COUNTER-clockwise on the xy plane

    else:
        if k == 0:
            next_pt = path.points[k + 1]
            v = normalize_vector(Vector.from_start_end(point, next_pt))
            normal = [-v[1], v[0], v[2]
                      ]  # rotate 90 degrees COUNTER-clockwise on the xy plane
        else:  # k == len(path.points)-1:
            prev_pt = path.points[k - 1]
            v = normalize_vector(Vector.from_start_end(point, prev_pt))
            normal = [v[1], -v[0],
                      v[2]]  # rotate 90 degrees clockwise on the xy plane

    if length_vector(normal) == 0:
        # When the neighboring elements happen to cancel out, then search for the true normal,
        # and project it on the xy plane for consistency
        normal = get_closest_mesh_normal_to_pt(mesh, point)
        normal = [normal[0], normal[1], 0]

    normal = normalize_vector(normal)
    normal = Vector(*list(normal))
    return normal
Exemple #20
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())
Exemple #21
0
    def vertex_normal(self, vertex):
        """Return the normal vector at the vertex as the weighted average of the
        normals of the neighboring faces.

        Parameters
        ----------
        key : int
            The identifier of the vertex.

        Returns
        -------
        list
            The components of the normal vector.
        """
        if not self.is_vertex_on_boundary(vertex):
            return

        halffaces = []
        for halfface in self.vertex_halffaces(vertex):
            if self.is_halfface_on_boundary(halfface):
                halffaces.append(halfface)

        vectors = [
            self.face_normal(halfface, False) for halfface in halffaces
            if halfface is not None
        ]
        return normalize_vector(centroid_points(vectors))
Exemple #22
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
def test_axis_and_angle():
    axis1 = normalize_vector([-0.043, -0.254, 0.617])
    angle1 = 0.1
    R = Rotation.from_axis_and_angle(axis1, angle1)
    axis2, angle2 = R.axis_and_angle
    assert allclose(axis1, axis2)
    assert allclose([angle1], [angle2])
Exemple #24
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
Exemple #25
0
def _draw_arc(normal_1, normal_2, origin):
    mid_pt = normalize_vector(add_vectors(normal_1, normal_2))
    arc    = Arc(Point3d(*[sum(axis) for axis in zip(normal_1, origin)]),
                 Point3d(*[sum(axis) for axis in zip(mid_pt, origin)]),
                 Point3d(*[sum(axis) for axis in zip(normal_2, origin)]))
    arc_as_curve = ArcCurve(arc)
    return arc_as_curve
Exemple #26
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
Exemple #27
0
def test_axis_and_angle_from_matrix():
    axis1 = normalize_vector([-0.043, -0.254, 0.617])
    angle1 = 0.1
    R = matrix_from_axis_and_angle(axis1, angle1)
    axis2, angle2 = axis_and_angle_from_matrix(R)
    assert allclose(axis1, axis2)
    assert allclose([angle1], [angle2])
Exemple #28
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)
Exemple #29
0
 def edge_vector(self, u, v, unitized=True):
     u_xyz = self.vertex_coordinates(u)
     v_xyz = self.vertex_coordinates(v)
     vector = subtract_vectors(v_xyz, u_xyz)
     if unitized:
         return normalize_vector(vector)
     return vector
Exemple #30
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