Ejemplo n.º 1
0
    def area(self):
        points = [v._position for v in self._vertices]
        first_tri = points[:3]

        area_first = geometry.area_tri(*first_tri)

        # For quads
        if len(first_tri) <= 3:
            return area_first

        second_tri = points[1:]
        return area_first + geometry.area_tri(*second_tri)
Ejemplo n.º 2
0
def triangle_random_points(num_points, loop_triangles):
    """
    Generates a list of random points over mesh loop triangles.

    :arg num_points: the number of random points to generate on each triangle.
    :type int:
    :arg loop_triangles: list of the triangles to generate points on.
    :type loop_triangles: :class:`bpy.types.MeshLoopTriangle`, sequence
    :return: list of random points over all triangles.
    :rtype: list
    """

    from random import random
    from mathutils.geometry import area_tri

    # For each triangle, generate the required number of random points
    sampled_points = [None] * (num_points * len(loop_triangles))
    for i, lt in enumerate(loop_triangles):
        # Get triangle vertex coordinates
        verts = lt.id_data.vertices
        ltv = lt.vertices[:]
        tv = (verts[ltv[0]].co, verts[ltv[1]].co, verts[ltv[2]].co)

        for k in range(num_points):
            # If this is a quad, we need to weight its 2 tris by their area
            if len(tv) != 1:
                area1 = area_tri(*tv[0])
                area2 = area_tri(*tv[1])
                area_tot = area1 + area2

                area1 = area1 / area_tot
                area2 = area2 / area_tot

                vecs = tv[0 if (random() < area1) else 1]
            else:
                vecs = tv[0]

            u1 = random()
            u2 = random()
            u_tot = u1 + u2

            if u_tot > 1:
                u1 = 1.0 - u1
                u2 = 1.0 - u2

            side1 = vecs[1] - vecs[0]
            side2 = vecs[2] - vecs[0]

            p = vecs[0] + u1 * side1 + u2 * side2

            sampled_points[num_points * i + k] = p

    return sampled_points
Ejemplo n.º 3
0
def distribute_points_accurate(bl_verts, tri_faces, number, tri_weights, proportional = True):
    if proportional:
        # returns list of numbers which mean how many points should be created on face according its area
        weighed_face_areas = [area_tri(*[bl_verts[i] for i in f]) * w for f, w in zip(tri_faces, tri_weights)]
    else:
        weighed_face_areas = tri_weights
    face_numbers = [0 for _ in tri_faces]
    chosen_faces = random.choices(range(len(tri_faces)), weighed_face_areas, k=number)
    for i in chosen_faces:
        face_numbers[i] += 1
    return face_numbers
Ejemplo n.º 4
0
def distribute_points_fast(bl_verts, tri_faces, number):
    # returns list of numbers which mean how many points should be created on face according its area
    # actually this function has much better performance but for whole algorithm it does not matter
    # leave this function unused
    face_areas = [area_tri(*[bl_verts[i] for i in f]) for f in tri_faces]
    total_area = sum(face_areas)
    face_numbers = [int(area * number / total_area) for area in face_areas]
    chosen_faces = random.choices(range(len(tri_faces)), face_areas, k=number-sum(face_numbers))
    for i in chosen_faces:
        face_numbers[i] += 1
    return face_numbers
Ejemplo n.º 5
0
    def tri_face_areas(self):
        if not self._tri_face_areas:
            if isinstance(self._verts, np.ndarray):
                self._tri_face_areas = np_calc_tris_areas(self._verts[np.array(
                    self._tri_faces)])
            else:
                self._tri_face_areas = [
                    area_tri(*[self._verts[i] for i in f])
                    for f in self._tri_faces
                ]

        return self._tri_face_areas
Ejemplo n.º 6
0
def center_of_gravity(obj):
    """
    Return a Vector with the coordinates of the center of gravity of the
    object, relatively to the object location. It assumes a uniform
    distribution of mass.  It can only work with triangular and quad meshes.
    """
    x = y = z = 0
    orig = Vector((0, 0, 0))
    for face in obj.data.polygons:
        if face.normal.length == 0.0:
            continue
        distance = distance_point_to_plane(orig, face.center, face.normal)

        nb_edges = len(face.vertices)
        v = [obj.data.vertices[f].co for f in face.vertices]
        if nb_edges == 3:
            face_vol = - face.area * distance / 3
            x += face_vol * (v[0][0] + v[1][0] + v[2][0]) / 4
            y += face_vol * (v[0][1] + v[1][1] + v[2][1]) / 4
            z += face_vol * (v[0][2] + v[1][2] + v[2][2]) / 4
        elif nb_edges == 4:
            # let's cut the quad in triangles!
            # triangle 1: vertices 0, 1, 2
            area1 = area_tri(v[0], v[1], v[2])
            face_vol1 = - area1 * distance / 3
            x += face_vol1 * (v[0][0] + v[1][0] + v[2][0]) / 4
            y += face_vol1 * (v[0][1] + v[1][1] + v[2][1]) / 4
            z += face_vol1 * (v[0][2] + v[1][2] + v[2][2]) / 4
            # triangle 2: vertices 2, 3, 0
            area2 = area_tri(v[2], v[3], v[0])
            face_vol2 = - area2 * distance / 3
            x += face_vol2 * (v[0][0] + v[2][0] + v[3][0]) / 4
            y += face_vol2 * (v[0][1] + v[2][1] + v[3][1]) / 4
            z += face_vol2 * (v[0][2] + v[2][2] + v[3][2]) / 4
        else:
            raise OrientationException

    return Vector((x, y, z))
Ejemplo n.º 7
0
 def outline_normal(self, edge, face, center_to_edge=None):
     # outlineとedgeが平面ならcenter_to_edgeを返す
     vec1, vec2 = edge.vertices[0].co, edge.vertices[1].co
     if center_to_edge is None:  # 外部でまだ計算していない場合
         v1c = face.center - vec1
         center_to_edge = v1c.project(vec2 - vec1) - v1c
         center_to_edge.normalize()  # == normal
     # normal長を調整
     cvs = [None, None]
     for i, v in enumerate(edge.vertices):
         for e in (e for e in v.edges if e != edge):
             if (e.vertices[0].co - e.vertices[1].co).length > MIN_NUMBER:
                 if not self.usehidden and e.hide:
                     if len(e.faces) == 1:
                         cv = e.vert_another(v)
                         cvs[i] = cv.co
                         break
     if cvs[0] is None and cvs[1] is None:  # 隣接無し。普通は有り得ない
         return center_to_edge
     elif cvs[0] and cvs[1]:  # 2
         if geo.area_tri(vec1, vec2, cvs[1]) >= MIN_NUMBER or \
            geo.area_tri(vec2, cvs[1], cvs[0]) >= MIN_NUMBER:
             edge_normal = geo.normal(vec1, vec2, cvs[1], cvs[0])
         else:
             return center_to_edge
     else:  # 1
         if cvs[0] and geo.area_tri(cvs[0], vec1, vec2):
             edge_normal = geo.normal(cvs[0], vec1, vec2)
         elif cvs[1] and geo.area_tri(vec1, vec2, cvs[1]):
             edge_normal = geo.normal(vec1, vec2, cvs[1])
         else:
             return center_to_edge
     if edge_normal.dot(center_to_edge) < 0.0:
         edge_normal.negate()
     angle = center_to_edge.angle(edge_normal)
     if math.pi / 2 - angle >= self.threthold:  # 平行でない
         center_to_edge /= math.cos(angle)
     return edge_normal
Ejemplo n.º 8
0
def calcArea():
    global totalArea
    totalArea = 0
    for poly in bm_tess.polygons:
        uno = bm_tess.uv_layers.active.data[poly.loop_indices[0]].uv
        dos = bm_tess.uv_layers.active.data[poly.loop_indices[1]].uv
        tres = bm_tess.uv_layers.active.data[poly.loop_indices[2]].uv
        area = area_tri(uno, dos, tres)
        totalArea += area

    bpy.data.meshes.remove(
        bm_tess,
        do_unlink=True,
        do_id_user=True,
        do_ui_user=True)
Ejemplo n.º 9
0
def calculateTriangleArea(mesh, vertices, matrix):
    vcs = [matrix*mesh.vertices[i].co for i in vertices]
    return area_tri(*vcs)
Ejemplo n.º 10
0
    def correct_tessellate(cls, polyline, tri_indices, sort=False):
        """不正な面の修正。
          v4----v        v4-------v
          /      \      /          \
         /        \   v1----v2     v3
        v1---v2---v3         \     /
                              v---v
        v1-v2-3がほぼ直線の場合でもv1-v2-v3に面が貼られる場合が有るので、
        v1-v2-v4, v2-v3-v4で貼り直す。

        :param polyline: 1つの面を構成するBMLoopかVectorのリスト
        :type polyline: list[BMLoop | Vector] | tuple[BMLoop | Vector]
        :param tri_indices: polylineにおいて三角形を構成するインデックスの
            二次元リスト。
        :type tri_indices: list[(int, int, int)] | tuple[(int, int, int)]
        :param sort: triの先頭要素でソートする
        :type sort: bool
        :return: インデックスの二次元リスト。
        :rtype: list[(int, int, int)]
        """
        n = len(polyline)
        if n <= 3:
            return [(0, 1, 2)]
        is_loop = isinstance(polyline[0], bmesh.types.BMLoop)
        if is_loop:
            vectors = [loop.vert.co for loop in polyline]
        else:
            vectors = polyline

        new_tris = []
        removed_tris = set()
        corrected_faces_num = 0

        for tri in tri_indices:
            v1, v2, v3 = tri

            if tri in removed_tris:
                continue
            if is_loop:
                area = geom.area_tri(polyline[v1].vert.co,
                                     polyline[v2].vert.co,
                                     polyline[v3].vert.co)
            else:
                area = geom.area_tri(polyline[v1], polyline[v2], polyline[v3])
            if area > cls.AREA_THRESHOLD:
                continue

            # a-bが連続しているように並び替え
            if (v1 + 1) % n == v2:
                if (v1 - 1) % n == v3:
                    v1, v2, v3 = v3, v1, v2
            elif (v2 + 1) % n == v3:
                v1, v2, v3 = v2, v3, v1
            elif (v3 + 1) % n == v1:
                if (v3 - 1) % n == v2:
                    v1, v2, v3 = v2, v3, v1
                else:
                    v1, v2, v3 = v3, v1, v2
            else:
                # 修正が必要な構造ではない
                continue

            vec1 = vectors[v1]
            vec2 = vectors[v2]
            vec3 = vectors[v3]

            if (v2 + 1) % n == v3:
                # v----v---------v
                #  \            /
                #  v1 -- v2 -- v3
                v5, v6 = v1, v3
                fill_143 = False
            else:
                if (vec2 - vec1).dot(vec3 - vec1) < 0:
                    #   v--------v
                    #  /          \
                    # v3      v1---v2
                    #  \     /
                    #   v---v
                    v5, v6 = v3, v2
                    fill_143 = True
                else:
                    #   v---------v
                    #  /           \
                    # v1---v2      v3
                    #        \     /
                    #         v---v
                    v5, v6 = v1, v3
                    fill_143 = False

            for link_tri in tri_indices:
                if link_tri != tri:
                    if v5 in link_tri and v6 in link_tri:
                        break
            else:
                link_tri = None

            if link_tri:
                v4 = link_tri[link_tri.index(v5) - 1]
                tri1 = (v1, v2, v4)
                if fill_143:
                    tri2 = (v1, v4, v3)
                else:
                    tri2 = (v2, v3, v4)
                new_tris.append(tri1)
                new_tris.append(tri2)
                removed_tris.add(tri)
                removed_tris.add(link_tri)

                corrected_faces_num += 1

        r_tri_indices = [tuple(tri) for tri in tri_indices]
        for tri in removed_tris:
            r_tri_indices.remove(tri)
        for tri in new_tris:
            r_tri_indices.append(tri)
        if sort:
            for tri in r_tri_indices:
                tri.sort()
            r_tri_indices.sort(key=lambda tri: tri[0])
        return r_tri_indices
Ejemplo n.º 11
0
def calculateTriangleArea(mesh, vertices, matrix):
    vcs = [matrix * mesh.vertices[i].co for i in vertices]
    return area_tri(*vcs)
Ejemplo n.º 12
0
 def tri_face_areas(self):
     if not self._tri_face_areas:
         self._tri_face_areas = [
             area_tri(*[self._verts[i] for i in f]) for f in self._tri_faces
         ]
     return self._tri_face_areas
Ejemplo n.º 13
0
 def calc_area(self):
     """:rtype: float"""
     return geom.area_tri(*self.coords)
def face_random_points_ngons(num_points, tessfaces):

    from random import random
    import mathutils
    from mathutils.geometry import area_tri, tessellate_polygon

    # Split all quads into 2 tris, tris remain unchanged
    tri_faces = []
    for f in tessfaces:
        tris = []
        verts = f.id_data.vertices
        fv = f.vertices[:]

        if len(fv) == 3:
            tris.append((verts[fv[0]].co, verts[fv[1]].co, verts[fv[2]].co))
        elif len(fv) == 4:
            tris.append((verts[fv[0]].co, verts[fv[1]].co, verts[fv[2]].co))
            tris.append((verts[fv[0]].co, verts[fv[3]].co, verts[fv[2]].co))
        else:
            fvngon = [v.co for v in verts]
            tris.extend([[fvngon[i] for i in tess]
                         for tess in tessellate_polygon([fvngon])])

        tri_faces.append(tris)

    # For each face, generate the required number of random points
    sampled_points = [None] * (num_points * len(tessfaces))
    # sampled points need to be vectorized as npo below
    for i, tf, npo in enumerate(zip(tri_faces, num_points)):
        for k in range(npo):
            # If this is a quad, we need to weight its 2 tris by their area
            if len(tf) == 2:

                area1 = area_tri(*tf[0])
                area2 = area_tri(*tf[1])
                area_tot = area1 + area2
                area1 = area1 / area_tot
                area2 = area2 / area_tot
                vecs = tf[0 if (random() < area1) else 1]

            elif len(tf) == 1:

                vecs = tf[0]

            else:

                areas = [area_tri(*tface) for tface in tf]
                area_tot = sum(areas)
                areas = [(area / area_tot) for area in areas]

                #  vecs = tf[0 if (random() < area1) else 1]   ???

            u1 = random()
            u2 = random()
            u_tot = u1 + u2

            if u_tot > 1:
                u1 = 1.0 - u1
                u2 = 1.0 - u2

            side1 = vecs[1] - vecs[0]
            side2 = vecs[2] - vecs[0]

            p = vecs[0] + u1 * side1 + u2 * side2

            sampled_points[npo * i + k] = p

    return sampled_points
Ejemplo n.º 15
0
def face_random_points(num_points, tessfaces):
    """
    Generates a list of random points over mesh tessfaces.

    :arg num_points: the number of random points to generate on each face.
    :type int:
    :arg tessfaces: list of the faces to generate points on.
    :type tessfaces: :class:`bpy.types.MeshTessFace`, sequence
    :return: list of random points over all faces.
    :rtype: list
    """

    from random import random
    from mathutils.geometry import area_tri

    # Split all quads into 2 tris, tris remain unchanged
    tri_faces = []
    for f in tessfaces:
        tris = []
        verts = f.id_data.vertices
        fv = f.vertices[:]
        tris.append((
            verts[fv[0]].co,
            verts[fv[1]].co,
            verts[fv[2]].co,
        ))
        if len(fv) == 4:
            tris.append((
                verts[fv[0]].co,
                verts[fv[3]].co,
                verts[fv[2]].co,
            ))
        tri_faces.append(tris)

    # For each face, generate the required number of random points
    sampled_points = [None] * (num_points * len(tessfaces))
    for i, tf in enumerate(tri_faces):
        for k in range(num_points):
            # If this is a quad, we need to weight its 2 tris by their area
            if len(tf) != 1:
                area1 = area_tri(*tf[0])
                area2 = area_tri(*tf[1])
                area_tot = area1 + area2

                area1 = area1 / area_tot
                area2 = area2 / area_tot

                vecs = tf[0 if (random() < area1) else 1]
            else:
                vecs = tf[0]

            u1 = random()
            u2 = random()
            u_tot = u1 + u2

            if u_tot > 1:
                u1 = 1.0 - u1
                u2 = 1.0 - u2

            side1 = vecs[1] - vecs[0]
            side2 = vecs[2] - vecs[0]

            p = vecs[0] + u1 * side1 + u2 * side2

            sampled_points[num_points * i + k] = p

    return sampled_points
Ejemplo n.º 16
0
def face_random_points(num_points, tessfaces):
    """
    Generates a list of random points over mesh tessfaces.

    :arg num_points: the number of random points to generate on each face.
    :type int:
    :arg tessfaces: list of the faces to generate points on.
    :type tessfaces: :class:`bpy.types.MeshTessFace`, sequence
    :return: list of random points over all faces.
    :rtype: list
    """

    from random import random
    from mathutils.geometry import area_tri

    # Split all quads into 2 tris, tris remain unchanged
    tri_faces = []
    for f in tessfaces:
        tris = []
        verts = f.id_data.vertices
        fv = f.vertices[:]
        tris.append((verts[fv[0]].co,
                     verts[fv[1]].co,
                     verts[fv[2]].co,
                    ))
        if len(fv) == 4:
            tris.append((verts[fv[0]].co,
                         verts[fv[3]].co,
                         verts[fv[2]].co,
                        ))
        tri_faces.append(tris)

    # For each face, generate the required number of random points
    sampled_points = [None] * (num_points * len(tessfaces))
    for i, tf in enumerate(tri_faces):
        for k in range(num_points):
            # If this is a quad, we need to weight its 2 tris by their area
            if len(tf) != 1:
                area1 = area_tri(*tf[0])
                area2 = area_tri(*tf[1])
                area_tot = area1 + area2

                area1 = area1 / area_tot
                area2 = area2 / area_tot

                vecs = tf[0 if (random() < area1) else 1]
            else:
                vecs = tf[0]

            u1 = random()
            u2 = random()
            u_tot = u1 + u2

            if u_tot > 1:
                u1 = 1.0 - u1
                u2 = 1.0 - u2

            side1 = vecs[1] - vecs[0]
            side2 = vecs[2] - vecs[0]

            p = vecs[0] + u1 * side1 + u2 * side2

            sampled_points[num_points * i + k] = p

    return sampled_points
Ejemplo n.º 17
0
 def calc_area(self):
     return geom.area_tri(*self.coords)
Ejemplo n.º 18
0
                    #print("    reverting verti  ces")
                    v1 = e.verts[1]
                    v2 = e.verts[0]
                lfverts[0]=Vector((v1.co))
                lfverts[1]=Vector((v2.co))
                nonCommonVIndex = list(set([v.index for v in lf.verts]) ^ set([v1.index,v2.index]))[0]
                lfverts[2]=Vector((bm.verts[nonCommonVIndex].co))
                areaOld = lf.calc_area()
                flatFace(lfverts)
                vectorAlF = vertices[vertsDictionary[v1.index]]-vertices[vertsDictionary[v2.index]]
                vectorTF = lfverts[0]-lfverts[1]
                q = vectorTF.rotation_difference(vectorAlF)
                for v in lfverts:
                    v.rotate(q)
                faceTranslate(vertices[vertsDictionary[v1.index]]-lfverts[0],lfverts)
                areaNew = mg.area_tri(lfverts[0], lfverts[1], lfverts[2])
                addFace(vertices, faces, lfverts, lf.index, [v1.index,v2.index,nonCommonVIndex])
                flatted.append(lf.index)
                #print("   flatted %d, old area=%2.2g new area=%2.2g"%(lf.index,areaOld,areaNew))
                refFace.append(lf)
                managedEdge = True

        #print("Finished managing edges")
        if not managedEdge:
            #print("+-- no adjacent to flat, remove from list bfaces")
            if f in bfaces:
                bfaces.remove(f)
        #print("List faces still to manage:%d"%(len(refFace)))
        #for i,face in enumerate(refFace):
            #print("       --+[%d] %d"%(i,face.index))
def face_random_points_ngons(num_points, tessfaces):

    from random import random
    import mathutils
    from mathutils.geometry import area_tri, tessellate_polygon

    # Split all quads into 2 tris, tris remain unchanged
    tri_faces = []
    for f in tessfaces:
        tris = []
        verts = f.id_data.vertices
        fv = f.vertices[:]

        if len(fv) == 3:
            tris.append((verts[fv[0]].co, verts[fv[1]].co, verts[fv[2]].co))
        elif len(fv) == 4:
            tris.append((verts[fv[0]].co, verts[fv[1]].co, verts[fv[2]].co))
            tris.append((verts[fv[0]].co, verts[fv[3]].co, verts[fv[2]].co))
        else:
            fvngon = [v.co for v in verts]
            tris.extend([[fvngon[i] for i in tess] for tess in tessellate_polygon([fvngon])])

        tri_faces.append(tris)

    # For each face, generate the required number of random points
    sampled_points = [None] * (num_points * len(tessfaces))
    # sampled points need to be vectorized as npo below
    for i, tf, npo in enumerate(zip(tri_faces,num_points)):
        for k in range(npo):
            # If this is a quad, we need to weight its 2 tris by their area
            if len(tf) == 2:

                area1 = area_tri(*tf[0])
                area2 = area_tri(*tf[1])
                area_tot = area1 + area2
                area1 = area1 / area_tot
                area2 = area2 / area_tot
                vecs = tf[0 if (random() < area1) else 1]

            elif len(tf) == 1:

                vecs = tf[0]

            else:

                areas = [area_tri(*tface) for tface in tf]
                area_tot = sum(areas)
                areas = [(area / area_tot) for area in areas]

                #  vecs = tf[0 if (random() < area1) else 1]   ???

            u1 = random()
            u2 = random()
            u_tot = u1 + u2

            if u_tot > 1:
                u1 = 1.0 - u1
                u2 = 1.0 - u2

            side1 = vecs[1] - vecs[0]
            side2 = vecs[2] - vecs[0]

            p = vecs[0] + u1 * side1 + u2 * side2

            sampled_points[npo * i + k] = p

    return sampled_points
Ejemplo n.º 20
0
 def calc_area(self):
     return geom.area_tri(*self.coords)