示例#1
0
    def vertex_area(self, key):
        """Compute the tributary area of a vertex.

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

        Returns
        -------
        float
            The tributary are.

        """
        area = 0.

        p0 = self.vertex_coordinates(key)

        for nbr in self.halfedge[key]:
            p1 = self.vertex_coordinates(nbr)
            v1 = subtract_vectors(p1, p0)

            fkey = self.halfedge[key][nbr]
            if fkey is not None:
                p2 = self.face_centroid(fkey)
                v2 = subtract_vectors(p2, p0)
                area += length_vector(cross_vectors(v1, v2))

            fkey = self.halfedge[nbr][key]
            if fkey is not None:
                p3 = self.face_centroid(fkey)
                v3 = subtract_vectors(p3, p0)
                area += length_vector(cross_vectors(v1, v3))

        return 0.25 * area
示例#2
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
示例#3
0
    def calculate_selfweight(xyz):
        fkey_centroid = {
            fkey: mesh.face_centroid(fkey)
            for fkey in mesh.faces()
        }

        for u in mesh.vertices():
            i = key_index[u]
            p0 = xyz[i]
            a = 0

            for v in mesh.halfedge[u]:
                j = key_index[v]
                p1 = xyz[j]
                p01 = [p1[axis] - p0[axis] for axis in range(3)]

                fkey = mesh.halfedge[u][v]
                if fkey in fkey_centroid:
                    p2 = fkey_centroid[fkey]
                    p02 = [p2[axis] - p0[axis] for axis in range(3)]
                    a += 0.25 * length_vector(cross_vectors(p01, p02))

                fkey = mesh.halfedge[v][u]
                if fkey in fkey_centroid:
                    p3 = fkey_centroid[fkey]
                    p03 = [p3[axis] - p0[axis] for axis in range(3)]
                    a += 0.25 * length_vector(cross_vectors(p01, p03))

            sw[i] = a * ro[i]

        return sw
示例#4
0
def intersection_plane_plane(plane1, plane2, tol=1e-6):
    """Computes the intersection of two planes

    Parameters
    ----------
    plane1 : tuple
        The base point and normal (normalized) defining the 1st plane.
    plane2 : tuple
        The base point and normal (normalized) defining the 2nd plane.
    tol : float, optional
        A tolerance for membership verification.
        Default is ``1e-6``.

    Returns
    -------
    line : tuple
        Two points defining the intersection line. None if planes are parallel.

    """
    o1, n1 = plane1
    o2, n2 = plane2

    if fabs(dot_vectors(n1, n2)) >= 1 - tol:
        return None

    # direction of intersection line
    d = cross_vectors(n1, n2)
    # vector in plane 1 perpendicular to the direction of the intersection line
    v1 = cross_vectors(d, n1)
    # point on plane 1
    p1 = add_vectors(o1, v1)

    x1 = intersection_line_plane((o1, p1), plane2, tol=tol)
    x2 = add_vectors(x1, d)
    return x1, x2
示例#5
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
示例#6
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
示例#7
0
    def from_points(cls, point, point_xaxis, point_xyplane):
        """Constructs a frame from 3 points.

        Parameters
        ----------
        point : point
            The origin of the frame.
        point_xaxis : point
            A point on the x-axis of the frame.
        point_xyplane : point
            A point within the xy-plane of the frame.

        Returns
        -------
        :class:`compas.geometry.Frame`
            The constructed frame.

        Examples
        --------
        >>> frame = Frame.from_points([0, 0, 0], [1, 0, 0], [0, 1, 0])
        >>> frame.point
        Point(0.000, 0.000, 0.000)
        >>> frame.xaxis
        Vector(1.000, 0.000, 0.000)
        >>> frame.yaxis
        Vector(0.000, 1.000, 0.000)
        """
        xaxis = subtract_vectors(point_xaxis, point)
        xyvec = subtract_vectors(point_xyplane, point)
        yaxis = cross_vectors(cross_vectors(xaxis, xyvec), xaxis)
        return cls(point, xaxis, yaxis)
def orthonormals_from_two_vectors(u, v):
    """Given two non-parallel vectors, creates a set of three orthonormal vectors.

    Parameters
    ----------
    u : (sequence of float) – XYZ components of the first vector.
    v : (sequence of float) – XYZ components of the second vector.

    Returns
    -------
    list
        The three orthonormal vectors.

    """

    k = cross_vectors(u, v)
    # check if vectors are parallel
    if np.linalg.norm(k) == 0.0:
        sys.exit('Input vectors cannot be parallel.')
    k = k / np.linalg.norm(k)
    i = u / np.linalg.norm(u)
    j = cross_vectors(k, i)
    j = j / np.linalg.norm(j)

    return [i, j, k]
示例#9
0
    def _tributary_areas(self, xyz):
        mesh = self.mesh
        key_index = self.key_index
        fkey_index = self.fkey_index
        is_loaded = self.is_loaded

        C = self.F.dot(xyz)

        areas = zeros((xyz.shape[0], 1))
        for u in mesh.vertices():
            p0 = xyz[key_index[u]]

            a = 0
            for v in mesh.halfedge[u]:
                p1 = xyz[key_index[v]]
                p01 = p1 - p0

                fkey = mesh.halfedge[u][v]
                if fkey is not None and is_loaded[fkey]:
                    p2 = C[fkey_index[fkey]]
                    a += 0.25 * length_vector(cross_vectors(p01, p2 - p0))

                fkey = mesh.halfedge[v][u]
                if fkey is not None and is_loaded[fkey]:
                    p3 = C[fkey_index[fkey]]
                    a += 0.25 * length_vector(cross_vectors(p01, p3 - p0))

            areas[key_index[u]] = a

        return areas
示例#10
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
示例#11
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
示例#12
0
def _triangle_xform(triangle):
    o = triangle[0]
    u = triangle[1] - o
    v = triangle[2] - o
    w = cross_vectors(u, v)
    v = cross_vectors(w, u)
    A = normalizerow(array([u, v, w])).T
    return o, A
示例#13
0
class LoadUpdater(object):
    """"""
    def __init__(self, mesh, p0, thickness=1.0, density=1.0, live=0.0):
        self.mesh       = mesh
        self.p0         = p0
        self.thickness  = thickness
        self.density    = density
        self.live       = live
        self.key_index  = mesh.key_index()
        self.fkey_index = {fkey: index for index, fkey in enumerate(mesh.faces())}
        self.is_loaded  = {fkey: mesh.get_face_attribute(fkey, 'is_loaded') for fkey in mesh.faces()}
        self.F          = self.face_matrix()
        
    def __call__(self, p, xyz):
        ta = self._tributary_areas(xyz)
        sw = ta * self.thickness * self.density + ta * self.live
        p[:, 2] = self.p0[:, 2] + sw[:, 0]


    def face_matrix(self):
        face_vertices = [None] * self.mesh.number_of_faces()
        for fkey in self.mesh.fes():
            face_vertices[self.fkey_index[fkey]] = [self.key_index[key] for key in self.mesh.face_vertices(fkey)]
        return face_matrix(face_vertices, rtype='csr', normalize=True)

    def _tributary_areas(self, xyz):ac
        mesh       = self.mesh
        key_index  = self.key_index
        fkey_index = self.fkey_index
        is_loaded  = self.is_loaded

        C = self.F.dot(xyz)

        areas = zeros((xyz.shape[0], 1))
        for u in mesh.vertices():
            p0 = xyz[key_index[u]]

            a = 0
            for v in mesh.halfedge[u]:
                p1  = xyz[key_index[v]]
                p01 = p1 - p0

                fkey = mesh.halfedge[u][v]
                if fkey is not None and is_loaded[fkey]:
                    p2 = C[fkey_index[fkey]]
                    a += 0.25 * length_vector(cross_vectors(p01, p2 - p0))

                fkey = mesh.halfedge[v][u]
                if fkey is not None and is_loaded[fkey]:
                    p3 = C[fkey_index[fkey]]
                    a += 0.25 * length_vector(cross_vectors(p01, p3 - p0))

            areas[key_index[u]] = a

        return areas
def orthonormal_vectors(vec_1, vec_2):
    """
    create a set of three orthonormal vectors 
    vec_1 & vec_2: list of three floats
    return a set of the three orthonormal vectors
    """
    vec_cros_1=cross_vectors(vec_1, vec_2)
    vec_cros_2=cross_vectors(vec_cros_1, vec_1)
    vec_list=normalize_vectors([vec_1, vec_cros_1, vec_cros_2])

    return vec_list
    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
示例#16
0
def get_boundary_plane(boundary):
    a = cablenet.vertex_coordinates(boundary[0])
    b = cablenet.vertex_coordinates(boundary[-1])

    x_axis = subtract_vectors(b, a)
    y_axis = [0, 0, 1.0]
    z_axis = cross_vectors(x_axis, y_axis)

    x_axis = cross_vectors(y_axis, z_axis)

    frame_0 = Frame(a, x_axis, y_axis)
    point = add_vectors(frame_0.point, scale_vector(frame_0.zaxis, OFFSET))
    frame_1 = Frame(point, x_axis, y_axis)
    return frame_0, frame_1
示例#17
0
def intersection_line_triangle(line, triangle, tol=1e-6):
    """Computes the intersection point of a line (ray) and a triangle
    based on the Moeller Trumbore intersection algorithm

    Parameters
    ----------
    line : [point, point] | :class:`compas.geometry.Line`
        Two points defining the line.
    triangle : [point, point, point]
        XYZ coordinates of the triangle corners.
    tol : float, optional
        A tolerance for membership verification.

    Returns
    -------
    [float, float, float] | None
        The intersection point between the line and the triangle,
        or None if the line and the plane are parallel.

    """
    a, b, c = triangle
    ab = subtract_vectors(b, a)
    ac = subtract_vectors(c, a)
    n = cross_vectors(ab, ac)
    plane = a, n

    x = intersection_line_plane(line, plane, tol=tol)

    if x:
        if is_point_in_triangle(x, triangle):
            return x
示例#18
0
 def DrawForeground(self, e):
     draw_dot = e.Display.DrawDot
     draw_arrows = e.Display.DrawArrows
     a = self.mouse.p1
     b = self.mouse.p2
     ab = subtract_vectors(b, a)
     Lab = length_vector(ab)
     if not Lab:
         return
     for index, vertex in enumerate(self.force_vertex_xyz):
         c = self.force_vertex_xyz[vertex]
         D = length_vector(
             cross_vectors(subtract_vectors(a, c), subtract_vectors(b, c)))
         if D / Lab < self.tol:
             point = Point3d(*c)
             draw_dot(point, str(index), self.dotcolor, self.textcolor)
             lines = List[Line](len(self.force_vertex_edges[vertex]))
             for u, v in self.force_vertex_edges[vertex]:
                 lines.Add(
                     Line(Point3d(*self.force_vertex_xyz[u]),
                          Point3d(*self.force_vertex_xyz[v])))
             draw_arrows(lines, self.linecolor)
             lines = List[Line](len(self.form_face_edges[vertex]))
             for u, v in self.form_face_edges[vertex]:
                 lines.Add(
                     Line(Point3d(*self.form_vertex_xyz[u]),
                          Point3d(*self.form_vertex_xyz[v])))
             draw_arrows(lines, self.linecolor)
             break
示例#19
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()
示例#20
0
    def DrawForeground(self, e):
        p1 = self.mouse.p1
        p2 = self.mouse.p2
        v12 = subtract_vectors(p2, p1)
        l12 = length_vector(v12)

        # force diagram
        for ckey in self.volmesh.cell:
            p0 = self.volmesh.cell_center(ckey)
            v01 = subtract_vectors(p1, p0)
            v02 = subtract_vectors(p2, p0)
            l = length_vector(cross_vectors(v01, v02))
            color = self.edgecolor
            if self.color_dict:
                color = FromArgb(*self.color_dict[ckey])
            if l12 == 0.0 or (l / l12) < self.tol:
                for hfkey in self.volmesh.cell_halffaces(ckey):
                    vkeys = self.volmesh.halfface_vertices(hfkey)
                    face_coordinates = [
                        self.volmesh.vertex_coordinates(vkey) for vkey in vkeys
                    ]
                    face_coordinates.append(face_coordinates[0])
                    polygon_xyz = [Point3d(*xyz) for xyz in face_coordinates]
                    e.Display.DrawPolyline(polygon_xyz, color, 3)
                break
示例#21
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
示例#22
0
def intersection_line_triangle(line, triangle, tol=1e-6):
    """Computes the intersection point of a line (ray) and a triangle
    based on the Moeller Trumbore intersection algorithm

    Parameters
    ----------
    line : tuple
        Two points defining the line.
    triangle : list of list of float
        XYZ coordinates of the triangle corners.
    tol : float, optional
        A tolerance for membership verification.
        Default is ``1e-6``.

    Returns
    -------
    point or None

    """
    a, b, c = triangle
    ab = subtract_vectors(b, a)
    ac = subtract_vectors(c, a)
    n = cross_vectors(ab, ac)
    plane = a, n

    x = intersection_line_plane(line, plane, tol=tol)

    if x:
        if is_point_in_triangle(x, triangle):
            return x
示例#23
0
def basis_vectors_from_matrix(R):
    """Returns the basis vectors from the rotation matrix R.

    Raises
    ------
    ValueError
        If rotation matrix is invalid.

    Returns
    -------
    list of two vectors
        The X and Y basis vectors of the rotation.

    Examples
    --------
    >>> from compas.geometry import Frame
    >>> f = Frame([0, 0, 0], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15])
    >>> R = matrix_from_frame(f)
    >>> xaxis, yaxis = basis_vectors_from_matrix(R)

    """
    xaxis = [R[0][0], R[1][0], R[2][0]]
    yaxis = [R[0][1], R[1][1], R[2][1]]
    zaxis = [R[0][2], R[1][2], R[2][2]]

    if not allclose(zaxis, cross_vectors(xaxis, yaxis)):
        raise ValueError("Matrix is invalid rotation matrix.")

    return [xaxis, yaxis]
示例#24
0
def world_to_local_coords_numpy(frame, xyz):
    """Convert global coordinates to local coordinates.

    Parameters
    ----------
    frame : :class:`Frame` or [point, xaxis, yaxis]
        The local coordinate system.
    xyz : array-like
        The global coordinates of the points to convert.

    Returns
    -------
    array
        The coordinates of the given points in the local coordinate system.

    Examples
    --------
    >>> import numpy as np
    >>> frame = Frame([0, 1, 0], [3, 4, 1], [1, 5, 9])
    >>> xyz = [Point(2, 3, 5)]
    >>> rst = world_to_local_coords_numpy(frame, xyz)
    >>> np.allclose(rst, [[3.726, 4.088, 1.550]], rtol=1e-3)
    True
    """
    origin = frame[0]
    uvw = [frame[1], frame[2], cross_vectors(frame[1], frame[2])]
    uvw = asarray(uvw).T
    xyz = asarray(xyz).T - asarray(origin).reshape((-1, 1))
    rst = solve(uvw, xyz)
    return rst.T
示例#25
0
def local_to_world_coords_numpy(frame, rst):
    """Convert local coordinates to global (world) coordinates.

    Parameters
    ----------
    frame : :class:`Frame` or [point, xaxis, yaxis]
        The local coordinate system.
    rst : array-like
        The coordinates of the points wrt the local coordinate system.

    Returns
    -------
    array
        The world coordinates of the given points.

    Notes
    -----
    ``origin`` and ``uvw`` together form the frame of local coordinates.

    Examples
    --------
    >>> frame = Frame([0, 1, 0], [3, 4, 1], [1, 5, 9])
    >>> rst = [Point(3.726, 4.088, 1.550)]
    >>> xyz = local_to_world_coords_numpy(frame, rst)
    >>> numpy.allclose(xyz, [[2.000, 3.000, 5.000]], rtol=1e-3)
    True
    """
    origin = frame[0]
    uvw = [frame[1], frame[2], cross_vectors(frame[1], frame[2])]

    uvw = asarray(uvw).T
    rst = asarray(rst).T
    xyz = uvw.dot(rst) + asarray(origin).reshape((-1, 1))
    return xyz.T
示例#26
0
def trimesh_edge_cotangent(mesh, u, v):
    """Compute the cotangent of the angle opposite a halfedge of the triangle mesh.

    Parameters
    ----------
    mesh : compas.datastructures.Mesh
        The triangle mesh data structure.
    u : int
        The identifier of the first vertex of the halfedge.
    v : int
        The identifier of the second vertex of the halfedge.

    Returns
    -------
    float
        The edge cotangent.

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

        pass

    """
    fkey = mesh.halfedge[u][v]
    cotangent = 0.0
    if fkey is not None:
        w = mesh.face_vertex_ancestor(fkey, u)
        wu = mesh.edge_vector(w, u)
        wv = mesh.edge_vector(w, v)
        l = length_vector(cross_vectors(wu, wv))
        if l:
            cotangent = dot_vectors(wu, wv) / l
    return cotangent
示例#27
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)
def convex_polygon_area_compas(polygon_vertices):
    """Compute the area of a convex polygon using compas.

    Parameters
    ----------
    polygon : sequence
        The XY 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.
    """

    polygon = Polygon(polygon_vertices)
    if not polygon.is_convex:
        sys.exit("the polygon is not convex.")

    vectors = []
    centroid = polygon.centroid
    area = 0.0
    for p in polygon.points:
        vectors.append(Vector.from_start_end(centroid, p))
    for i in range(len(vectors)):
        area += cross_vectors(vectors[i - 1], vectors[i])[2] / 2

    return area
示例#29
0
def trimesh_edge_cotangent(mesh, u, v):
    """Compute the cotangent of the angle opposite a halfedge of the triangle mesh.

    Parameters
    ----------
    mesh : :class:`compas.datastructures.Mesh`
        Instance of mesh.
    u : int
        The identifier of the first vertex of the halfedge.
    v : int
        The identifier of the second vertex of the halfedge.

    Returns
    -------
    float
        The edge cotangent.

    """
    fkey = mesh.halfedge[u][v]
    cotangent = 0.0
    if fkey is not None:
        w = mesh.face_vertex_ancestor(fkey, u)
        wu = mesh.edge_vector(w, u)
        wv = mesh.edge_vector(w, v)
        length = length_vector(cross_vectors(wu, wv))
        if length:
            cotangent = dot_vectors(wu, wv) / length
    return cotangent
示例#30
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