Пример #1
0
def camera_as_planes(scene, obj):
    """
    Return planes in world-space which represent the camera view bounds.
    """
    from mathutils.geometry import normal

    camera = obj.data
    # normalize to ignore camera scale
    matrix = obj.matrix_world.normalized()
    frame = [matrix * Vector(v) for v in camera.view_frame(scene)]
    origin = matrix.to_translation()

    planes = []
    is_persp = (camera.type != 'ORTHO')
    for i in range(4):
        # find the 3rd point to define the planes direction
        if is_persp:
            frame_other = origin
        else:
            frame_other = frame[i] + matrix.col[2].xyz

        n = normal(frame_other, frame[i - 1], frame[i])
        d = -n.dot(frame_other)
        planes.append((n, d))

    if not is_persp:
        # add a 5th plane to ignore objects behind the view
        n = normal(frame[0], frame[1], frame[2])
        d = -n.dot(origin)
        planes.append((n, d))

    return planes
Пример #2
0
def normal(*vecs):
    # 3~4個のVectorのNormalを求める
    if len(vecs) == 3:
        return geom.normal(*vecs)
    elif len(vecs) == 4:
        n1 = geom.normal(vecs[0], vecs[1], vecs[3])
        n2 = geom.normal(vecs[1], vecs[2], vecs[3])
        if n1.dot(n2) < 0:
            n2.negate()
        return (n1 + n2).normalized()
def get_color_from_normal(dvk, pol, num_verts, vectorlight, colo):
    if num_verts <= 4:
        normal_no = normal(dvk[pol[0]], dvk[pol[1]], dvk[pol[2]])
    else:
        normal_no = normal(dvk[pol[0]], dvk[pol[1]], dvk[pol[2]], dvk[pol[3]])

    normal_no = (normal_no.angle(vectorlight, 0)) / pi

    r = (normal_no * colo[0]) - 0.1
    g = (normal_no * colo[1]) - 0.1
    b = (normal_no * colo[2]) - 0.1
    return (r + 0.2, g + 0.2, b + 0.2)
Пример #4
0
def get_color_from_normal(dvk, pol, num_verts, vectorlight, colo):
    if num_verts <= 4:
        normal_no = normal(dvk[pol[0]], dvk[pol[1]], dvk[pol[2]])
    else:
        normal_no = normal(dvk[pol[0]], dvk[pol[1]], dvk[pol[2]], dvk[pol[3]])

    normal_no = (normal_no.angle(vectorlight, 0)) / pi

    r = (normal_no * colo[0]) - 0.1
    g = (normal_no * colo[1]) - 0.1
    b = (normal_no * colo[2]) - 0.1
    return (r+0.2, g+0.2, b+0.2)
Пример #5
0
def generate_3PT_mode_1(pts, obj, nv):
    origin = obj.location
    mw = obj.matrix_world
    V = Vector

    nv = max(3, nv)

    # construction
    v1, v2, v3, v4 = V(pts[0]), V(pts[1]), V(pts[1]), V(pts[2])
    edge1_mid = v1.lerp(v2, 0.5)
    edge2_mid = v3.lerp(v4, 0.5)
    axis = geometry.normal(v1, v2, v4)
    mat_rot = mathutils.Matrix.Rotation(math.radians(90.0), 4, axis)

    # triangle edges
    v1_ = ((v1 - edge1_mid) * mat_rot) + edge1_mid
    v2_ = ((v2 - edge1_mid) * mat_rot) + edge1_mid
    v3_ = ((v3 - edge2_mid) * mat_rot) + edge2_mid
    v4_ = ((v4 - edge2_mid) * mat_rot) + edge2_mid

    r = geometry.intersect_line_line(v1_, v2_, v3_, v4_)
    if r:
        p1, _ = r
        cp = mw * p1
        bpy.context.scene.cursor_location = cp
        layer = get_layer()
        generate_gp3d_stroke(layer, p1, v1, axis, mw, origin, nv)
    else:
        print('not on a circle')
Пример #6
0
def write_triangle(f, tri):
    f.write("facet normal %f %f %f\n" % normal(*tri)[:])
    f.write("  outer loop\n")
    for vert in tri:
        f.write("    vertex %f %f %f\n" % vert[:])
    f.write("  endloop\n")
    f.write("endfacet\n")
Пример #7
0
def _binary_write(filepath, faces):
    with open(filepath, 'wb') as data:
        fw = data.write
        # header
        # we write padding at header beginning to avoid to
        # call len(list(faces)) which may be expensive
        fw(struct.calcsize('<80sI') * b'\0')

        # 3 vertex == 9f
        pack = struct.Struct('<9f').pack

        # number of vertices written
        nb = 0

        for face in faces:
            # calculate face normal
            # write normal + vertexes + pad as attributes
            fw(struct.pack('<3f', *normal(*face)) + pack(*itertools.chain.from_iterable(face)))
            # attribute byte count (unused)
            fw(b'\0\0') 
            nb += 1

        # header, with correct value now
        data.seek(0)
        fw(struct.pack('<80sI', _header_version().encode('ascii'), nb))
Пример #8
0
 def calc_vert_normal(self, vert, looptris, fallback=Vector((0, 0, 0))):
     normal = Vector()
     num = 0
     for tri in looptris:
         normal += geom.normal(*[loop.vert.co for loop in tri])
         num += 1
     return normal / num
Пример #9
0
 def __init__(self, v1, v2, v3):
     self.verts = [v1, v2, v3]
     self.normal = geom.normal(v1.co, v2.co, v3.co)
     self.edge_keys = [tuple(sorted((self.verts[i - 1], self.verts[i]),
                                    key=lambda v: v.index))
                       for i in range(3)]
     self.outer_verts = []
Пример #10
0
def generate_3PT(pts, obj, nv, mode=1):
    mw = obj.matrix_world
    V = Vector
    nv = max(3, nv)

    # construction
    v1, v2, v3, v4 = V(pts[0]), V(pts[1]), V(pts[1]), V(pts[2])
    edge1_mid = v1.lerp(v2, 0.5)
    edge2_mid = v3.lerp(v4, 0.5)
    axis = geometry.normal(v1, v2, v4)
    mat_rot = mathutils.Matrix.Rotation(math.radians(90.0), 4, axis)

    # triangle edges
    v1_ = ((v1 - edge1_mid) * mat_rot) + edge1_mid
    v2_ = ((v2 - edge1_mid) * mat_rot) + edge1_mid
    v3_ = ((v3 - edge2_mid) * mat_rot) + edge2_mid
    v4_ = ((v4 - edge2_mid) * mat_rot) + edge2_mid

    r = geometry.intersect_line_line(v1_, v2_, v3_, v4_)
    if r:
        p1, _ = r
        cp = mw * p1
        bpy.context.scene.cursor_location = cp

        if mode == 0:
            pass

        elif mode == 1:
            generate_bmesh_repr(p1, v1, axis, nv)

    else:
        print('not on a circle')
Пример #11
0
def generate_3PT(pts, obj, nv, mode=1):
    mw = obj.matrix_world
    V = Vector
    nv = max(3, nv)

    # construction
    v1, v2, v3, v4 = V(pts[0]), V(pts[1]), V(pts[1]), V(pts[2])
    edge1_mid = v1.lerp(v2, 0.5)
    edge2_mid = v3.lerp(v4, 0.5)
    axis = geometry.normal(v1, v2, v4)
    mat_rot = mathutils.Matrix.Rotation(math.radians(90.0), 4, axis)

    # triangle edges
    v1_ = ((v1 - edge1_mid) * mat_rot) + edge1_mid
    v2_ = ((v2 - edge1_mid) * mat_rot) + edge1_mid
    v3_ = ((v3 - edge2_mid) * mat_rot) + edge2_mid
    v4_ = ((v4 - edge2_mid) * mat_rot) + edge2_mid

    r = geometry.intersect_line_line(v1_, v2_, v3_, v4_)
    if r:
        p1, _ = r
        cp = mw * p1
        bpy.context.scene.cursor_location = cp

        if mode == 0:
            pass

        elif mode == 1:
            generate_bmesh_repr(p1, v1, axis, nv)

    else:
        print('not on a circle')
Пример #12
0
 def calc_vert_normal(self, vert, looptris, fallback=Vector((0, 0, 0))):
     normal = Vector()
     num = 0
     for tri in looptris:
         normal += geom.normal(*[loop.vert.co for loop in tri])
         num += 1
     return normal / num
Пример #13
0
def generate_3PT_mode_1_(pts, obj):
    origin = obj.location
    transform_matrix = obj.matrix_local
    V = Vector

    # construction
    v1, v2, v3, v4 = V(pts[0]), V(pts[1]), V(pts[1]), V(pts[2])
    edge1_mid = v1.lerp(v2, 0.5)
    edge2_mid = v3.lerp(v4, 0.5)
    axis = geometry.normal(v1, v2, v4)
    mat_rot = mathutils.Matrix.Rotation(math.radians(90.0), 4, axis)

    # triangle edges
    v1_ = ((v1 - edge1_mid) * mat_rot) + edge1_mid
    v2_ = ((v2 - edge1_mid) * mat_rot) + edge1_mid
    v3_ = ((v3 - edge2_mid) * mat_rot) + edge2_mid
    v4_ = ((v4 - edge2_mid) * mat_rot) + edge2_mid

    r = geometry.intersect_line_line(v1_, v2_, v3_, v4_)
    if r:
        p1, _ = r
        # cp = transform_matrix * (p1 + origin)
        cp = transform_matrix * p1
        bpy.context.scene.cursor_location = cp
        # generate_gp3d_stroke(cp, axis, obj, radius=(p1-v1).length)
    else:
        print('not on a circle')
Пример #14
0
def generate_3PT_mode_1_(pts, obj):
    origin = obj.location
    transform_matrix = obj.matrix_local
    V = Vector

    # construction
    v1, v2, v3, v4 = V(pts[0]), V(pts[1]), V(pts[1]), V(pts[2])
    edge1_mid = v1.lerp(v2, 0.5)
    edge2_mid = v3.lerp(v4, 0.5)
    axis = geometry.normal(v1, v2, v4)
    mat_rot = mathutils.Matrix.Rotation(math.radians(90.0), 4, axis)

    # triangle edges
    v1_ = ((v1 - edge1_mid) * mat_rot) + edge1_mid
    v2_ = ((v2 - edge1_mid) * mat_rot) + edge1_mid
    v3_ = ((v3 - edge2_mid) * mat_rot) + edge2_mid
    v4_ = ((v4 - edge2_mid) * mat_rot) + edge2_mid

    r = geometry.intersect_line_line(v1_, v2_, v3_, v4_)
    if r:
        p1, _ = r
        # cp = transform_matrix * (p1 + origin)
        cp = transform_matrix * p1
        bpy.context.scene.cursor_location = cp
        # generate_gp3d_stroke(cp, axis, obj, radius=(p1-v1).length)
    else:
        print('not on a circle')
Пример #15
0
 def calc_normals(self):
     """
     Face normals
     """
     normals = np.empty((len(self.faces), 3))
     for idx, face in enumerate(self.faces):
         normals[idx] = normal(self.vertices[face])
     self.faces.normals = normals
Пример #16
0
def getPolyNormal(poly):
	""" Returns the normal of poligon based on the position of their vertex. It calculates the normal, it doesn't return manually modified normals.

	:param poly: The poligon.
	:type poly: |KX_PolyProxy|
	"""

	mesh = poly.getMesh()
	s = poly.getNumVertex()
	v1 = mesh.getVertex(0, poly.v1)
	v2 = mesh.getVertex(0, poly.v2)
	v3 = mesh.getVertex(0, poly.v3)
	if s == 4: v4v = mesh.getVertex(0, poly.v4).XYZ
	else: v4v = None

	if v4v: normal = geometry.normal(v1.XYZ, v2.XYZ, v3.XYZ, v4v)
	else: normal = geometry.normal(v1.XYZ, v2.XYZ, v3.XYZ)
	return normal
Пример #17
0
    def execute(self, context):
        C = context
        D = bpy.data
        ob = C.active_object

        #if bpy.app.debug != True:
        #    bpy.app.debug = True
        #    if C.active_object.show_extra_indices != True:
        #        C.active_object.show_extra_indices = True
        if ob.mode == 'OBJECT':
            me = C.object.data
            bm = bmesh.new()
            bm.from_mesh(me)
        else:
            obj = C.edit_object
            me = obj.data
            bm = bmesh.from_edit_mesh(me)
        bm.select_history.validate()
        if len(bm.select_history) < 3:
            self.report({'INFO'}, 'Pick three vertices first')
            return {'CANCELLED'}

        points3Index = []
        points3 = []
        _ordering = bm.select_history if self.ref_order == "first" else list(
            bm.select_history)[::-1]
        for i in _ordering:
            if len(points3) >= 3:
                break
            elif isinstance(i, bmesh.types.BMVert):
                points3.append(i.co)
                points3Index.append(i.index)
        print(points3Index)
        if len(points3) < 3:
            self.report({'INFO'},
                        'At least three vertices are needed being selected')
            return {'CANCELLED'}

        points3Normal = normal(*points3)
        for v in bm.verts:
            if v.select and v.index not in points3Index:
                _move = True
                if self.filter_distance > 0.0:
                    _move = abs(
                        distance_point_to_plane(
                            v.co, points3[0],
                            points3Normal)) < self.filter_distance
                if _move == True:
                    v.co = intersect_line_plane(v.co, v.co + points3Normal,
                                                points3[0], points3Normal)
        if ob.mode == 'OBJECT':
            bm.to_mesh(me)
            bm.free()
        else:
            bmesh.update_edit_mesh(me, True)

        return {'FINISHED'}
Пример #18
0
def createMirror(angle):
    mirror[0].xyz = [0,-1,-1]
    mirror[1].xyz = [-1,1,1]
    mirror[2].xyz = [1,1,1]
    mirror[0].rotate( Matrix.Rotation( angle, 4, norm_mirror) )
    mirror[1].rotate( Matrix.Rotation( angle, 4, norm_mirror)  )
    mirror[2].rotate( Matrix.Rotation( angle, 4, norm_mirror)  )
    n = geometry.normal(mirror[2],mirror[1],mirror[0])
    return [mirror[2],mirror[1],mirror[0],n]
Пример #19
0
def flatFace(verts):
    #print("    Flatface: original vertices %s %s %s"%(verts[0],verts[1],verts[2]))
    quatr = mg.normal(verts).rotation_difference(Vector((0, 0, 1)))
    eul = quatr.to_euler()
    eul.z = 0.0
    #print("    Flatface called Euler is x=%2.2g deg y=%2.2g deg"%(degrees(eul.x),degrees(eul.y)))
    for v in verts:
        v.rotate(eul)
        v.z = 0
Пример #20
0
 def execute(self, context):
     nor = normal(p.co for p in self.points[:3])
     co = Vector(self.points[-1].co) + nor * self.offset
     bpy.ops.mesh.bisect(plane_co=co,
                         plane_no=nor,
                         use_fill=self.use_fill,
                         clear_inner=self.clear_inner,
                         clear_outer=self.clear_outer)
     return {'FINISHED'}
Пример #21
0
    def execute(self, context):
        obj = context.edit_object
        me = obj.data
        bm = bmesh.from_edit_mesh(me)
        bm.select_history.validate()
        vertCount = 0
        selectedVerts = []
        for vert in (vert for vert in bm.verts if vert.select):  #count loop verts
            vertCount+=1
            if len(selectedVerts)<3:
                selectedVerts.append(vert)

        if vertCount < 1:
            self.report({'INFO'}, 'Select at least one vertex')
            return {'CANCELLED'}


        vertsMedianLoc = mathutils.Vector((0.0 ,0.0 ,0.0))
        vertsMedianNorm = mathutils.Vector((0.0 ,0.0 ,0.0))
        vertsCoordList = []
        vectOffset = mathutils.Vector((0.0, 0.0, self.Depth))
        offsetMatrix = mathutils.Matrix.Translation(vectOffset)
        yawMatrix = mathutils.Matrix.Rotation(radians(self.TrimRoll), 4, 'X')
        pitchMatrix = mathutils.Matrix.Rotation(radians(self.TripPitch), 4, 'Y')

        for vert in selectedVerts:
            vertsMedianLoc+=vert.co
            vertsCoordList.append(vert.co)
            vertsMedianNorm+=vert.normal
        vertsMedianLoc /= len(selectedVerts)
        if vertCount>2:
            trisNorm=normal(vertsCoordList)
            if degrees(vertsMedianNorm.angle(trisNorm))>90:
                vertsMedianNorm= trisNorm*(-1)
            else:
                vertsMedianNorm = trisNorm
        if vertCount==2:  #fixes normal for 2 verts
            vectorV1_V2=selectedVerts[0].co-selectedVerts[1].co
            perpendicular= vectorV1_V2.cross(vertsMedianNorm)
            vertsMedianNorm = perpendicular.cross(vectorV1_V2)


        normToRotation = vertsMedianNorm.to_track_quat('Z', 'X').to_euler()
        selectionLocalMatrix = mathutils.Matrix.Translation(vertsMedianLoc)
        selectionLocalMatrix *= selectionLocalMatrix.Rotation(normToRotation[2], 4, 'Z')
        selectionLocalMatrix *= selectionLocalMatrix.Rotation(normToRotation[1], 4, 'Y')
        selectionLocalMatrix *= selectionLocalMatrix.Rotation(normToRotation[0], 4, 'X')

        spaceMatrixTransform = context.object.matrix_world*selectionLocalMatrix*offsetMatrix*yawMatrix*pitchMatrix

        loc = spaceMatrixTransform.to_translation()
        norm = spaceMatrixTransform.to_3x3()*mathutils.Vector((0.0, 0.0, 1.0))
        bpy.ops.mesh.select_all(action='SELECT')
        bpy.ops.mesh.bisect(plane_co=loc, plane_no=norm, use_fill=True, clear_inner= not self.clearOut, clear_outer=self.clearOut)
        bpy.ops.mesh.select_all(action='DESELECT')
        bmesh.update_edit_mesh(me, True)
        return {"FINISHED"}
Пример #22
0
def compute_intersect_circle_circle(params, result, gates):
    '''Compute two circles intersection(s)
    Result has to be [[],[],[]] to host the solutions
    Gates are as follow:
    0: Is there a intersection?
    1: First Intersection
    2: Second intersection
    3: The working plane is defined by its normal (True) or by a third point (False)'''
    center_a, radius_a, center_b, radius_b, plane_pt, plane_normal = params
    local_result = []
    sphere_loc_a = V(center_a)
    sphere_loc_b = V(center_b)
    if gates[3]:
        norm = V(plane_normal).normalized()
    else:
        v_in_plane = V(plane_pt)
        norm = normal([sphere_loc_a, sphere_loc_b, v_in_plane])
    if norm.length == 0:
        if gates[3]:
            print("Circle Intersection Error: the Normal can't be (0,0,0)")
        else:
            print("Circle Intersection Error: the point in plane is aligned with origins")

    is_2d = norm.x == 0 and norm.y == 0

    if is_2d and False:
        z_coord = sphere_loc_a.z
        inter_p = intersect_sphere_sphere_2d(sphere_loc_a.to_2d(), radius_a, sphere_loc_b.to_2d(), radius_b)
        if inter_p[0]:
            intersect = True
            vec1 = list(inter_p[1]) + [z_coord]
            vec0 = list(inter_p[0]) + [z_coord]
            local_result = [intersect, vec0, vec1]

    else:
        dist = (sphere_loc_a - sphere_loc_b).length
        new_a = V([0, 0, 0])
        new_b = V([dist, 0, 0])
        inter_p = intersect_sphere_sphere_2d(new_a.to_2d(), radius_a, new_b.to_2d(), radius_b)
        if inter_p[0]:
            intersect_num = True
            trird_point = sphere_loc_a + norm
            new_c = V([0, 0, 1])
            vec0 = barycentric_transform(inter_p[0].to_3d(), new_a, new_b, new_c, sphere_loc_a, sphere_loc_b, trird_point)
            vec1 = barycentric_transform(inter_p[1].to_3d(), new_a, new_b, new_c, sphere_loc_a, sphere_loc_b, trird_point)
            local_result = [intersect_num, list(vec0), list(vec1)]

    if not local_result:
        direc = (sphere_loc_b - sphere_loc_a).normalized()
        intersect_num = False
        vec0 = sphere_loc_a + direc * radius_a
        vec1 = sphere_loc_b - direc * radius_b
        local_result = [intersect_num, list(vec0), list(vec1)]

    for i, res in enumerate(result):
        if gates[i]:
            res.append(local_result[i])
Пример #23
0
def getPolyNormal(poly):
	""" Returns the normal of poligon based on the position of their vertex. It calculates the normal, it doesn't return manually modified normals.

	:param poly: The poligon.
	:type poly: |KX_PolyProxy|
	"""

	mesh = poly.getMesh()
	s = poly.getNumVertex()
	v1 = mesh.getVertex(0, poly.v1)
	v2 = mesh.getVertex(0, poly.v2)
	v3 = mesh.getVertex(0, poly.v3)
	if s == 4: v4v = mesh.getVertex(0, poly.v4).XYZ
	else: v4v = None

	if v4v: normal = geometry.normal(v1.XYZ, v2.XYZ, v3.XYZ, v4v)
	else: normal = geometry.normal(v1.XYZ, v2.XYZ, v3.XYZ)
	return normal
Пример #24
0
def createMirror(angle):
    mirror[0].xyz = [0, -1, -1]
    mirror[1].xyz = [-1, 1, 1]
    mirror[2].xyz = [1, 1, 1]
    mirror[0].rotate(Matrix.Rotation(angle, 4, norm_mirror))
    mirror[1].rotate(Matrix.Rotation(angle, 4, norm_mirror))
    mirror[2].rotate(Matrix.Rotation(angle, 4, norm_mirror))
    n = geometry.normal(mirror[2], mirror[1], mirror[0])
    return [mirror[2], mirror[1], mirror[0], n]
Пример #25
0
 def __init__(self, v1, v2, v3):
     self.verts = [v1, v2, v3]
     self.normal = geom.normal(v1.co, v2.co, v3.co)
     self.edge_keys = [
         tuple(
             sorted((self.verts[i - 1], self.verts[i]),
                    key=lambda v: v.index)) for i in range(3)
     ]
     self.outer_verts = []
Пример #26
0
def get_medians_and_normals(oper, context, mode):
    """
    because this is a post hoc implementation to cater for 2.8 ability to multi-select objects in 
    edit mode, this is a verbose routine. 

    """
    medians = []
    normals = []
    extra_data = None

    if mode == "ONE":
        obj_main = bpy.context.edit_object
        me = obj_main.data
        bm = bmesh.from_edit_mesh(me)

        # get active face indices
        faces = [f for f in bm.faces if f.select]
        if oper.flip_u:
            faces = list(reversed(faces))

        for f in faces:
            if len(medians) > 2:
                # dont select more than 2 faces.
                break
            normals.append(f.normal)
            medians.append(median(f))

        bevel_depth = (medians[0] - (faces[0].verts[0].co)).length
        scale2 = (medians[1] - (faces[1].verts[0].co)).length
        op2_scale = scale2 / bevel_depth
        extra_data = bevel_depth, scale2, op2_scale

    elif mode == "TWO":
        obj_one = bpy.context.selected_objects[0]
        obj_two = bpy.context.selected_objects[1]

        first_coords = []
        objs = [obj_two, obj_one] if oper.flip_u else [obj_one, obj_two]
        for obj in objs:
            m = obj.matrix_world
            bm = bmesh.from_edit_mesh(obj.data)

            # instead of transforming the entire bm using bmesh.ops.transform
            # we can multiply only the selected geometry. hopefully
            f = [f for f in bm.faces if f.select][0]
            first_coords.append(m @ f.verts[0].co)
            normals.append(normal([(m @ v.co) for v in f.verts]))
            medians.append(m @ median(f))

        bevel_depth = (medians[0] - first_coords[0]).length
        scale2 = (medians[1] - first_coords[1]).length
        op2_scale = scale2 / bevel_depth
        extra_data = bevel_depth, scale2, op2_scale

    return medians, normals, extra_data
Пример #27
0
    def execute(self, context):
        """ method called from ui """

        # init local
        catt_export = context.scene.catt_export

        # check for non flat faces
        if self.arg == 'check_nonflat_faces':

            # discard if no object selected
            sel_objects = bpy.context.selected_objects
            if( len(sel_objects) == 0 ):
                self.report({'INFO'}, 'No object selected.')
                return {'CANCELLED'}

            # switch to edit mode
            bpy.ops.object.mode_set(mode = 'EDIT')

            # context = bpy.context
            # obj = context.edit_object
            mesh = bpy.context.edit_object.data

            # select None
            bpy.ops.mesh.select_all(action='DESELECT')
            bm = bmesh.from_edit_mesh(mesh)
            ngons = [f for f in bm.faces if len(f.verts) > 3]

            # init locals
            has_non_flat_faces = False
            planar_tolerance = 1e-6

            # loop over faces
            for ngon in ngons:

                # define a plane from first 3 points
                co = ngon.verts[0].co
                norm = normal([v.co for v in ngon.verts[:3]])

                # set face selected
                ngon.select = not all( [abs(distance_point_to_plane(v.co, co, norm)) < planar_tolerance for v in ngon.verts[3:]] )

                # flag at least one non flat face detected
                if ngon.select:
                    has_non_flat_faces = True

            # update mesh
            bmesh.update_edit_mesh(mesh)

            # disable edit mode if no non-flat face detected
            if not has_non_flat_faces:
                bpy.ops.object.mode_set(mode = 'OBJECT')
                self.report({'INFO'}, 'No non-flat face detected.')

            return {'FINISHED'}
Пример #28
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
Пример #29
0
def _ascii_write(filepath, faces):
    with open(filepath, 'w') as data:
        fw = data.write
        header = _header_version()
        fw('solid %s\n' % header)

        for face in faces:
            # calculate face normal
            fw('facet normal %f %f %f\nouter loop\n' % normal(*face)[:])
            for vert in face:
                fw('vertex %f %f %f\n' % vert[:])
            fw('endloop\nendfacet\n')

        fw('endsolid %s\n' % header)
Пример #30
0
def build_mirror_pivot(f, verts, ob):
    v0 = mathutils.Vector(verts[f[0]])
    v1 = mathutils.Vector(verts[f[1]])
    v2 = mathutils.Vector(verts[f[2]])
    if len(f) == 4:
        v3 = mathutils.Vector(verts[f[3]])
        norm = normal(v0, v1, v2, v3)
    else:
        v3 = None
        norm = normal(v0, v1, v2)
    rot = norm.to_track_quat('X', 'Z')
    r = rot.to_euler('XYZ')
    p0 = v0.lerp(v1, 0.5)
    if v3 == None: p1 = v2
    else: p1 = v2.lerp(v3, 0.5)
    center = p0.lerp(p1, 0.5)

    dummy = bpy.data.objects.new(ob.name + "_mirror_pivot", None)
    dummy.location = center.to_tuple()
    print("ROTATING TO ", r.x, " ", r.y, " ", r.z)
    dummy.rotation_euler = (r.x, r.y, r.z)
    bpy.context.scene.objects.link(dummy)
    return dummy
Пример #31
0
def compute_palm(source_armature, suffix):
    h = get_bone_position(source_armature, 'hand.' + suffix)
    r = get_bone_position(source_armature, 'f_ring.01.' + suffix)
    i = get_bone_position(source_armature, 'f_index.01.' + suffix)
    m = get_bone_position(source_armature, 'f_middle.01.' + suffix)
    if not h:
        return None, None
    if not r or not i or not m:
        hand = get_bone(source_armature, 'hand.' + suffix )
        return (hand.head + hand.tail) / 2, hand.x_axis
    palm_co = (h + m) / 2
    palm_no = -geometry.normal((h, i, r))
    palm_no *= (h - m).length * 1
    return palm_co, palm_no
def build_mirror_pivot(f,verts,ob):
  v0 = mathutils.Vector(verts[f[0]])
  v1 = mathutils.Vector(verts[f[1]])
  v2 = mathutils.Vector(verts[f[2]])
  if len(f) == 4:
    v3 = mathutils.Vector(verts[f[3]])
    norm = normal(v0,v1,v2,v3)
  else:
    v3 = None
    norm = normal(v0,v1,v2)
  rot = norm.to_track_quat('X','Z')
  r = rot.to_euler('XYZ')
  p0 = v0.lerp(v1,0.5)
  if v3 == None: p1 = v2
  else: p1 = v2.lerp(v3,0.5)
  center = p0.lerp(p1,0.5)

  dummy = bpy.data.objects.new(ob.name + "_mirror_pivot",None)
  dummy.location = center.to_tuple()
  print("ROTATING TO ",r.x," ",r.y," ",r.z)
  dummy.rotation_euler = (r.x,r.y,r.z)
  bpy.context.scene.objects.link(dummy)
  return dummy
Пример #33
0
def generate_3PT_mode_1(pts=None, num_verts=20, make_edges=False):
    '''
    Arc from start - throught - Eend
    - call this function only if you have 3 pts,
    - do your error checking before passing to it.
    '''
    num_verts -= 1
    verts, edges = [], []
    V = Vector

    # construction
    v1, v2, v3, v4 = V(pts[0]), V(pts[1]), V(pts[1]), V(pts[2])
    edge1_mid = v1.lerp(v2, 0.5)
    edge2_mid = v3.lerp(v4, 0.5)
    axis = geometry.normal(v1, v2, v4)
    mat_rot = mathutils.Matrix.Rotation(math.radians(90.0), 4, axis)

    # triangle edges
    v1_ = ((v1 - edge1_mid) * mat_rot) + edge1_mid
    v2_ = ((v2 - edge1_mid) * mat_rot) + edge1_mid
    v3_ = ((v3 - edge2_mid) * mat_rot) + edge2_mid
    v4_ = ((v4 - edge2_mid) * mat_rot) + edge2_mid

    r = geometry.intersect_line_line(v1_, v2_, v3_, v4_)
    if r:
        # do arc
        p1, _ = r

        # find arc angle.
        a = (v1 - p1).angle((v4 - p1), 0)
        s = (2 * math.pi) - a

        interior_angle = (v1 - v2).angle(v4 - v3, 0)
        if interior_angle > 0.5 * math.pi:
            s = math.pi + 2 * (0.5 * math.pi - interior_angle)

        for i in range(num_verts + 1):
            mat_rot = mathutils.Matrix.Rotation(((s / num_verts) * i), 4, axis)
            vec = ((v4 - p1) * mat_rot) + p1
            verts.append(vec[:])
    else:
        # do straight line
        step_size = 1 / num_verts
        verts = [v1_.lerp(v4_, i * step_size)[:] for i in range(num_verts + 1)]

    if make_edges:
        edges = [(n, n + 1) for n in range(len(verts) - 1)]

    return verts, edges
Пример #34
0
def generate_3PT_mode_1(pts=None, num_verts=20, make_edges=False):
    '''
    Arc from start - throught - Eend
    - call this function only if you have 3 pts,
    - do your error checking before passing to it.
    '''
    num_verts -= 1
    verts, edges = [], []
    V = Vector

    # construction
    v1, v2, v3, v4 = V(pts[0]), V(pts[1]), V(pts[1]), V(pts[2])
    edge1_mid = v1.lerp(v2, 0.5)
    edge2_mid = v3.lerp(v4, 0.5)
    axis = geometry.normal(v1, v2, v4)
    mat_rot = mathutils.Matrix.Rotation(math.radians(90.0), 4, axis)

    # triangle edges
    v1_ = ((v1 - edge1_mid) * mat_rot) + edge1_mid
    v2_ = ((v2 - edge1_mid) * mat_rot) + edge1_mid
    v3_ = ((v3 - edge2_mid) * mat_rot) + edge2_mid
    v4_ = ((v4 - edge2_mid) * mat_rot) + edge2_mid

    r = geometry.intersect_line_line(v1_, v2_, v3_, v4_)
    if r:
        # do arc
        p1, _ = r

        # find arc angle.
        a = (v1 - p1).angle((v4 - p1), 0)
        s = (2 * math.pi) - a

        interior_angle = (v1 - v2).angle(v4 - v3, 0)
        if interior_angle > 0.5 * math.pi:
            s = math.pi + 2 * (0.5 * math.pi - interior_angle)

        for i in range(num_verts + 1):
            mat_rot = mathutils.Matrix.Rotation(((s / num_verts) * i), 4, axis)
            vec = ((v4 - p1) * mat_rot) + p1
            verts.append(vec[:])
    else:
        # do straight line
        step_size = 1 / num_verts
        verts = [v1_.lerp(v4_, i * step_size)[:] for i in range(num_verts + 1)]

    if make_edges:
        edges = [(n, n + 1) for n in range(len(verts) - 1)]

    return verts, edges
def compute_distances_mu(plane, pts, result, gates, tolerance):
    plane_origin = V(plane[0])
    plane_a, plane_b = V(plane[1]), V(plane[2])
    norm = normal([plane_origin, plane_a, plane_b])
    if norm.length == 0:
        print("Error: the three points of the plane are aligned. Not valid plane")
    local_result = [[] for res in result]
    for p in pts:
        data = compute_point_tri_dist(V(p), plane_origin, plane_a, plane_b, norm, tolerance)
        for i, r in enumerate(local_result):
            r.append(data[i])

    for i, res in enumerate(result):
        if gates[i]:
            res.append(local_result[i])
Пример #36
0
def compute_distances_mu(plane, pts, result, gates, tolerance):
    plane_origin = V(plane[0])
    plane_a, plane_b = V(plane[1]), V(plane[2])
    norm = normal([plane_origin, plane_a, plane_b])
    if norm.length == 0:
        print("Error: the three points of the plane are aligned. Not valid plane")
    local_result = [[] for res in result]
    for p in pts:
        data = compute_point_tri_dist(V(p), plane_origin, plane_a, plane_b, norm, tolerance)
        for i, r in enumerate(local_result):
            r.append(data[i])

    for i, res in enumerate(result):
        if gates[i]:
            res.append(local_result[i])
Пример #37
0
def generate_3PT_mode_1(pts, obj, nv):
    origin = obj.location
    mw = obj.matrix_world
    V = Vector

    nv = max(3, nv)

    # construction
    v1, v2, v3, v4 = V(pts[0]), V(pts[1]), V(pts[1]), V(pts[2])
    edge1_mid = v1.lerp(v2, 0.5)
    edge2_mid = v3.lerp(v4, 0.5)
    axis = geometry.normal(v1, v2, v4)
    mat_rot = mathutils.Matrix.Rotation(math.radians(90.0), 4, axis)

    # triangle edges
    v1_ = ((v1 - edge1_mid) * mat_rot) + edge1_mid
    v2_ = ((v2 - edge1_mid) * mat_rot) + edge1_mid
    v3_ = ((v3 - edge2_mid) * mat_rot) + edge2_mid
    v4_ = ((v4 - edge2_mid) * mat_rot) + edge2_mid

    r = geometry.intersect_line_line(v1_, v2_, v3_, v4_)
    if r:
        p1, _ = r
        cp = mw * p1
        bpy.context.scene.cursor_location = cp
        layer = get_layer()
        generate_gp3d_stroke(layer, p1, v1, axis, mw, origin, nv)

        ''' 
        # f = [i for i in dir(bpy.context) if 'gpencil' in i]
        active_gpencil_frame
        active_gpencil_layer
        editable_gpencil_layers
        editable_gpencil_strokes
        gpencil_data
        gpencil_data_owner
        visible_gpencil_layers
        '''
        
        #bpy.context.active_gpencil_layer = layer
        #print(bpy.context.gpencil_data)
        scn = bpy.context.scene
        scn.grease_pencil = bpy.data.grease_pencil['tc_circle_000']

    else:
        print('not on a circle')
Пример #38
0
    def __init__(self, curveObj, objType=OBJTYPE_NONMODIFIER):

        self.bCurveObj = curveObj
        self.scale = curveObj.scale[:]
        curveCopyData = curveObj.data.copy()

        #Non-zero values of the following attributes impacts length
        curveCopyData.bevel_depth = 0
        curveCopyData.extrude = 0
        curveCopyData.offset = 0

        curveCopyObj = curveObj.copy()
        curveCopyObj.data = curveCopyData
        bpy.context.scene.collection.objects.link(curveCopyObj)

        if (objType == OBJTYPE_MODIFIER):
            depsgraph = bpy.context.evaluated_depsgraph_get()
            cmd = curveCopyObj.evaluated_get(depsgraph).to_mesh()
        else:
            cmd = curveCopyObj.to_mesh()

        self.curvePts = [cmd.vertices[cmd.edges[0].vertices[0]].co.copy()]
        self.curvePts += [
            cmd.vertices[e.vertices[1]].co.copy() for e in cmd.edges
        ]

        bpy.context.scene.collection.objects.unlink(curveCopyObj)
        bpy.data.objects.remove(curveCopyObj)

        self.curveLength = 0  #sum(s.calc_length() for s in curveObj.data.splines)
        self.mw = self.bCurveObj.matrix_world

        for i in range(0, len(self.curvePts)):
            self.curvePts[i] = self.mw @ self.curvePts[i]

            if (i > 0):
                segLen = (self.curvePts[i] - self.curvePts[i - 1]).length
                self.curveLength += segLen

        self.startCo = self.curvePts[0]
        self.endCo = self.curvePts[-1]

        self.curveNormal = geometry.normal(self.curvePts)
Пример #39
0
    def get_face_extras(self, geom):
        face_medians = []
        face_normals = []
        for obj_index, faces in enumerate(geom.faces):

            verts = geom.verts[obj_index]

            medians = []
            normals = []
            concat_median = medians.append
            concat_normal = normals.append

            for face in faces:
                poly_verts = [verts[idx] for idx in face]
                concat_normal(normal(poly_verts))
                concat_median(calc_median(poly_verts))

            face_medians.append(medians)
            face_normals.append(normals)

        return face_medians, face_normals
Пример #40
0
def generate_3PT(pts, obj, nv, mode=0):
    origin = obj.location
    mw = obj.matrix_world
    V = Vector

    nv = max(3, nv)

    # construction
    v1, v2, v3, v4 = V(pts[0]), V(pts[1]), V(pts[1]), V(pts[2])
    edge1_mid = v1.lerp(v2, 0.5)
    edge2_mid = v3.lerp(v4, 0.5)
    axis = geometry.normal(v1, v2, v4)
    mat_rot = mathutils.Matrix.Rotation(math.radians(90.0), 4, axis)

    # triangle edges
    v1_ = ((v1 - edge1_mid) * mat_rot) + edge1_mid
    v2_ = ((v2 - edge1_mid) * mat_rot) + edge1_mid
    v3_ = ((v3 - edge2_mid) * mat_rot) + edge2_mid
    v4_ = ((v4 - edge2_mid) * mat_rot) + edge2_mid

    r = geometry.intersect_line_line(v1_, v2_, v3_, v4_)
    if r:
        p1, _ = r
        cp = mw * p1
        bpy.context.scene.cursor_location = cp

        if mode == 0:
            layer = get_layer()
            generate_gp3d_stroke(layer, p1, v1, axis, mw, origin, nv)

            scn = bpy.context.scene
            scn.grease_pencil = bpy.data.grease_pencil['tc_circle_000']

        elif mode == 1:
            generate_bmesh_repr(p1, v1, axis, nv)

    else:
        print('not on a circle')
Пример #41
0
def polygons_geom(config, vecs, polygons, p_vertices, p_vertex_colors,
                  p_indices, v_path, p_cols, idx_p_offset, points_colors):
    '''generates polygons geometry'''

    if (config.color_per_polygon and not config.polygon_use_vertex_color
        ) or config.shade_mode == 'facet':

        polygon_indices, original_idx = ensure_triangles(
            vecs, polygons, config.handle_concave_quads)

        if config.shade_mode == 'facet':
            normals = [normal(*[Vector(vecs[c]) for c in p]) for p in polygons]

            if config.polygon_use_vertex_color:
                p_v, v_c, idx, total_p_verts = splitted_facet_polygons_geom_v_cols(
                    polygon_indices, original_idx, v_path, points_colors,
                    idx_p_offset[0], normals, config.vector_light)
            else:
                p_v, v_c, idx, total_p_verts = splitted_facet_polygons_geom(
                    polygon_indices, original_idx, v_path, p_cols,
                    idx_p_offset[0], normals, config.vector_light)

        elif config.shade_mode == 'smooth':
            normals = get_vertex_normals(vecs, polygons)
            p_v, v_c, idx, total_p_verts = splitted_smooth_polygons_geom(
                polygon_indices, original_idx, v_path, p_cols, idx_p_offset[0],
                normals, config.vector_light)

        else:
            p_v, v_c, idx, total_p_verts = splitted_polygons_geom(
                polygon_indices, original_idx, v_path, p_cols, idx_p_offset[0])

        p_vertices.extend(p_v)
        p_vertex_colors.extend(v_c)
        p_indices.extend(idx)
    else:
        polygon_indices, original_idx = ensure_triangles(
            vecs, polygons, config.handle_concave_quads)
        p_vertices.extend(v_path)

        if config.shade_mode == 'smooth':
            normals = get_vertex_normals(v_path, polygons)
            colors = []
            if config.polygon_use_vertex_color:
                for normal_v, col in zip(normals, points_colors):

                    factor = normal_v.dot(config.vector_light) * 0.5 + 0.5
                    colors.append([
                        col[0] * factor, col[1] * factor, col[2] * factor,
                        col[3]
                    ])
            else:
                col = p_cols
                for normal_v in normals:
                    factor = normal_v.dot(config.vector_light) * 0.5 + 0.5
                    colors.append([
                        col[0] * factor, col[1] * factor, col[2] * factor,
                        col[3]
                    ])
            p_vertex_colors.extend(colors)
        else:
            p_vertex_colors.extend([p_cols for v in v_path])
        p_indices.extend([[c + idx_p_offset[0] for c in p]
                          for p in polygon_indices])
        total_p_verts = len(vecs)
    idx_p_offset[0] += total_p_verts
Пример #42
0
def f_(me, list_0, dict_0, opp, list_fl, in_):

    if len(list_fl) == 0:      # loop
        loop = True
        path = False
        frst = list_0[0][0]
        list_1 = f_2(frst, list_0)
        del list_1[-1]

    else:      # path
        loop = False
        path = True
        frst = list_fl[0]
        last = list_fl[1]
        list_1 = f_1(frst, list_0, last)

    n = len(list_1)
    for ii in range(n):
        p_ = (me.vertices[list_1[ii]].co).copy()
        p1_ = (me.vertices[list_1[(ii - 1) % n]].co).copy()
        p2_ = (me.vertices[list_1[(ii + 1) % n]].co).copy()
        vec1_ = p_ - p1_
        vec2_ = p_ - p2_
        ang = vec1_.angle(vec2_, any)
        an = round(degrees(ang))

        if ang == 0 or ang == 180:
            continue
        elif ang != 0 or ang != 180:
            vec_no = normal(p_, p1_, p2_)
            break
        
    list_2 = []
    list_3 = []

    for i in range(n):
        p = (me.vertices[list_1[i]].co).copy()
        p1 = (me.vertices[list_1[(i - 1) % n]].co).copy()
        p2 = (me.vertices[list_1[(i + 1) % n]].co).copy()

        me.vertices[list_1[i]].select = False

        if in_ == True:
            p3 = p - (vec_no * opp)
        else:
            p3 = p + (vec_no * opp)

        me.vertices.add(1)
        me.vertices[-1].co = p3

        list_2.append(list_1[i])
        list_3.append(me.vertices[-1].index)

    n1 = len(list_2)
    if path == True:
        for j in range(n1 - 1):
            me.faces.add(1)
            me.faces[-1].vertices_raw = [ list_2[j], list_2[(j + 1) % n1], list_3[(j + 1) % n1], list_3[j] ]
    elif loop == True:
        for j in range(n1):
            me.faces.add(1)
            me.faces[-1].vertices_raw = [ list_2[j], list_2[(j + 1) % n1], list_3[(j + 1) % n1], list_3[j] ]

    # -- -- -- --
    list_4 = []
    n2 = len(list_2)
    for k in range(n2):

        q = (me.vertices[list_2[k]].co).copy()
        q1 = (me.vertices[list_2[(k - 1) % n2]].co).copy()
        q2 = (me.vertices[list_2[(k + 1) % n2]].co).copy()

        vec1 = q - q1
        vec2 = q - q2

        q3 = q - (vec1.normalized() * 0.1)
        q4 = q - (vec2.normalized() * 0.1)

        ang = vec1.angle(vec2, any)
        
        if path:
            if k == 0:
                axis = vec2
            elif k == n2 - 1:
                axis = -vec1
            else:
                axis = q3 - q4
            
            mtrx = Matrix.Rotation((pi * 0.5), 3, axis)
            q5 = (me.vertices[list_3[k]].co).copy()
            tmp = q5 - q
            tmp1 = mtrx * tmp
            tmp2 = tmp1 + q

            if k == 0:
                list_4.append(tmp2)
            elif k == n2 - 1:
                list_4.append(tmp2)
            else:
                vec3 = tmp2 - q
                adj = opp / tan(ang / 2)
                h = (adj ** 2 + opp ** 2) ** 0.5
                q6 = q + (vec3.normalized() * h)
                list_4.append(q6)

        elif loop:

            axis = q3 - q4
            ang = vec1.angle(vec2, any)

            mtrx = Matrix.Rotation((pi * 0.5), 3, axis)
            q5 = (me.vertices[list_3[k]].co).copy()
            tmp = q5 - q
            tmp1 = mtrx * tmp
            tmp2 = tmp1 + q

            vec3 = tmp2 - q
        
            # -- -- -- --
            d_ = tan(ang / 2)
            if d_ == 0:
                pass
            elif d_ != 0:
                adj = opp / tan(ang / 2)
                h = (adj ** 2 + opp ** 2) ** 0.5
                q6 = q + (vec3.normalized() * h)
                me.vertices[list_3[k]].co = q6
            # -- -- -- --

    if len(list_4) == 0:
        pass
    else:
        for kk in range(n2):
            me.vertices[list_3[kk]].co = list_4[kk]

    me.update(calc_edges = True)
    def process(self):
        if self.outputs['Centers'].is_linked or self.outputs['Normals'].is_linked or \
                self.outputs['Origins'].is_linked or self.outputs['Norm_abs'].is_linked:
            if 'Polygons' in self.inputs and 'Vertices' in self.inputs \
                and self.inputs['Polygons'].is_linked and self.inputs['Vertices'].is_linked:

                pols_ = SvGetSocketAnyType(self, self.inputs['Polygons'])
                vers_tupls = SvGetSocketAnyType(self, self.inputs['Vertices'])
                vers_vects = Vector_generate(vers_tupls)
                
                # make mesh temp утилитарно - удалить в конце
                mat_collect = []
                normals_out = []
                origins = []
                norm_abs_out = []
                for verst, versv, pols in zip(vers_tupls, vers_vects, pols_):
                    normals = []
                    centrs = []
                    norm_abs = []
                    p0_xdirs = []
                    for p in pols:
                        v0 = versv[p[0]]
                        v1 = versv[p[1]]
                        v2 = versv[p[2]]
                        # save direction of 1st point in polygon
                        p0_xdirs.append(v0)
                        # normals
                        norm = geometry.normal(v0, v1, v2)
                        normals.append(norm)                       
                        # centrs
                        x,y,z = zip(*[verst[poi] for poi in p])
                        x,y,z = sum(x)/len(x), sum(y)/len(y), sum(z)/len(z)
                        current_center = Vector((x,y,z))
                        centrs.append(current_center)
                        # normal absolute !!!
                        # это совершенно нормально!!! ;-)
                        norm_abs.append(current_center+norm)
                        
                        if self.Separate:
                            norm_abs_out.append(norm_abs)    
                            origins.append(centrs)
                            normals_out.append(normals)
                        else:
                            norm_abs_out.extend(norm_abs)    
                            origins.extend(centrs)
                            normals_out.extend(normals)
                    mat_collect_ = []

                    for cen, nor, p0 in zip(centrs, normals, p0_xdirs):
                        zdir = nor
                        xdir = (Vector(p0) - cen).normalized()
                        ydir = zdir.cross(xdir)
                        lM = [(xdir[0], ydir[0], zdir[0], cen[0]),
                              (xdir[1], ydir[1], zdir[1], cen[1]),
                              (xdir[2], ydir[2], zdir[2], cen[2]),
                              (0.0, 0.0, 0.0, 1.0)]
                        mat_collect_.append(lM)
                    mat_collect.extend(mat_collect_)

                if not self.Separate:
                    SvSetSocketAnyType(self, 'Centers', mat_collect)
                    SvSetSocketAnyType(self, 'Norm_abs', Vector_degenerate([norm_abs_out]))
                    SvSetSocketAnyType(self, 'Origins', Vector_degenerate([origins]))
                    SvSetSocketAnyType(self, 'Normals', Vector_degenerate([normals_out]))
                else:
                    SvSetSocketAnyType(self, 'Centers', mat_collect)
                    SvSetSocketAnyType(self, 'Norm_abs', Vector_degenerate(norm_abs_out))
                    SvSetSocketAnyType(self, 'Origins', Vector_degenerate(origins))
                    SvSetSocketAnyType(self, 'Normals', Vector_degenerate(normals_out))
Пример #44
0
 def calc_normal(self):
     """:rtype: Vector"""
     return geom.normal(*self.coords)
Пример #45
0
    def process(self):
        if self.outputs['Centers'].is_linked or self.outputs['Normals'].is_linked or \
                self.outputs['Origins'].is_linked or self.outputs['Norm_abs'].is_linked:
            if 'Polygons' in self.inputs and 'Vertices' in self.inputs \
                and self.inputs['Polygons'].is_linked and self.inputs['Vertices'].is_linked:

                pols_ = SvGetSocketAnyType(self, self.inputs['Polygons'])
                vers_tupls = SvGetSocketAnyType(self, self.inputs['Vertices'])
                vers_vects = Vector_generate(vers_tupls)
                
                # make mesh temp утилитарно - удалить в конце
                mat_collect = []
                normals_out = []
                origins = []
                norm_abs_out = []
                for verst, versv, pols in zip(vers_tupls, vers_vects, pols_):
                    # medians в векторах
                    medians = []
                    normals = []
                    centrs = []
                    norm_abs = []
                    for p in pols:
                        # medians
                        # it calcs middle point of opposite edges, 
                        # than finds length vector between this two points
                        v0 = versv[p[0]]
                        v1 = versv[p[1]]
                        v2 = versv[p[2]]
                        lp=len(p)
                        if lp >= 4:
                            l = ((lp-2)//2) + 2
                            v3 = versv[p[l]]
                            poi_2 = (v2+v3)/2
                            # normals
                            norm = geometry.normal(v0, v1, v2, v3)
                            normals.append(norm)
                        else:
                            poi_2 = v2
                            # normals
                            norm = geometry.normal(v0, v1, v2)
                            normals.append(norm)
                        poi_1 = (v0+v1)/2
                        vm = poi_2 - poi_1
                        medians.append(vm)
                        # centrs
                        x,y,z = zip(*[verst[poi] for poi in p])
                        x,y,z = sum(x)/len(x), sum(y)/len(y), sum(z)/len(z)
                        current_center = Vector((x,y,z))
                        centrs.append(current_center)
                        # normal absolute !!!
                        # это совершенно нормально!!! ;-)
                        norm_abs.append(current_center+norm)
                        
                    norm_abs_out.append(norm_abs)    
                    origins.append(centrs)
                    normals_out.extend(normals)
                    mat_collect_ = []
                    for cen, med, nor in zip(centrs, medians, normals):
                        loc = Matrix.Translation(cen)
                        # need better solution for Z,Y vectors + may be X vector correction
                        vecz = Vector((0, 1e-6, 1))
                        q_rot0 = vecz.rotation_difference(nor).to_matrix().to_4x4()
                        q_rot2 = nor.rotation_difference(vecz).to_matrix().to_4x4()
                        vecy = Vector((1e-6, 1, 0)) * q_rot2
                        q_rot1 = vecy.rotation_difference(med).to_matrix().to_4x4()
                        # loc is matrix * rot vector * rot vector
                        M = loc*q_rot1*q_rot0
                        lM = [ j[:] for j in M ]
                        mat_collect_.append(lM)
                    mat_collect.extend(mat_collect_)
                
                SvSetSocketAnyType(self, 'Centers', mat_collect)
                SvSetSocketAnyType(self, 'Norm_abs', Vector_degenerate(norm_abs_out))
                SvSetSocketAnyType(self, 'Origins', Vector_degenerate(origins))
                SvSetSocketAnyType(self, 'Normals', Vector_degenerate([normals_out]))
Пример #46
0
    def process(self):
        verts_socket, poly_socket = self.inputs
        norm_socket, norm_abs_socket, origins_socket, centers_socket = self.outputs

        if not any([s.is_linked for s in self.outputs]):
            return

        if not (verts_socket.is_linked and poly_socket.is_linked):
            return

        pols_ = poly_socket.sv_get()
        vers_tupls = verts_socket.sv_get()
        vers_vects = Vector_generate(vers_tupls)

        # make mesh temp утилитарно - удалить в конце
        mat_collect = []
        normals_out = []
        origins = []
        norm_abs_out = []
        for verst, versv, pols in zip(vers_tupls, vers_vects, pols_):
            normals = []
            centrs = []
            norm_abs = []
            p0_xdirs = []
            for p in pols:
                v0 = versv[p[0]]
                v1 = versv[p[1]]
                v2 = versv[p[2]]
                # save direction of 1st point in polygon
                p0_xdirs.append(v0)
                # normals
                norm = geometry.normal(v0, v1, v2)
                normals.append(norm)
                # centrs
                x,y,z = zip(*[verst[poi] for poi in p])
                x,y,z = sum(x)/len(x), sum(y)/len(y), sum(z)/len(z)
                current_center = Vector((x,y,z))
                centrs.append(current_center)
                # normal absolute !!!
                # это совершенно нормально!!! ;-)
                norm_abs.append(current_center+norm)

            if self.Separate:
                norm_abs_out.append(norm_abs)
                origins.append(centrs)
                normals_out.append(normals)
            else:
                norm_abs_out.extend(norm_abs)
                origins.extend(centrs)
                normals_out.extend(normals)
                
            mat_collect_ = []

            for cen, nor, p0 in zip(centrs, normals, p0_xdirs):
                zdir = nor
                xdir = (Vector(p0) - cen).normalized()
                ydir = zdir.cross(xdir)
                lM = [(xdir[0], ydir[0], zdir[0], cen[0]),
                      (xdir[1], ydir[1], zdir[1], cen[1]),
                      (xdir[2], ydir[2], zdir[2], cen[2]),
                      (0.0, 0.0, 0.0, 1.0)]
                mat_collect_.append(Matrix(lM))
            mat_collect.extend(mat_collect_)

        if not self.Separate:
            norm_abs_out = [norm_abs_out]
            origins = [origins]
            normals_out = [normals_out]

        centers_socket.sv_set(mat_collect)
        norm_abs_socket.sv_set(Vector_degenerate(norm_abs_out))
        origins_socket.sv_set(Vector_degenerate(origins))
        norm_socket.sv_set(Vector_degenerate(normals_out))
Пример #47
0
def convex_hull_3d(vecs, eps:'距離がこれ以下なら同一平面と見做す'=1e-6):
    """三次元又は二次元の凸包を求める"""
    if len(vecs) <= 1:
        return list(range(len(vecs)))

    verts = [_Vert(i, v) for i, v in enumerate(vecs)]

    # なるべく離れている二頂点を求める
    medium = reduce(lambda a, b: a + b, vecs) / len(vecs)
    v1 = max(verts, key=lambda v: (v.co - medium).length)
    v2 = max(verts, key=lambda v: (v.co - v1.co).length)
    line = v2.co - v1.co
    if line.length <= eps:
        # 全ての頂点が重なる
        return [0]

    verts.remove(v1)
    verts.remove(v2)
    if not verts:
        return [v1.index, v2.index]

    # 三角形を構成する為の頂点を求める
    v3 = max(verts, key=lambda v: line.cross(v.co - v1.co).length)
    if line.normalized().cross(v3.co - v1.co).length <= eps:
        # 全ての頂点が同一線上にある
        return [v1.index, v2.index]
    
    verts.remove(v3)
    if not verts:
        return [v1.index, v2.index, v3.index]

    # 四面体を構成する為の頂点を求める
    normal = geom.normal(v1.co, v2.co, v3.co)
    def key_func(v):
        return abs(geom.distance_point_to_plane(v.co, v1.co, normal))
    v4 = max(verts, key=key_func)
    if key_func(v4) <= eps:
        # 全ての頂点が平面上にある
        quat = normal.rotation_difference(Vector((0, 0, 1)))
        vecs_2d = [(quat * v).to_2d() for v in vecs]
        return convex_hull_2d(vecs_2d, eps)

    verts.remove(v4)

    # 四面体作成
    #       ^ normal
    #    v3 |
    #     / |\
    # v1 /____\v2
    #    \    /
    #     \  /
    #     v4

    if geom.distance_point_to_plane(v4.co, v1.co, normal) < 0.0:
        faces = [_Face(v1, v2, v3),
                 _Face(v1, v4, v2), _Face(v2, v4, v3), _Face(v3, v4, v1)]
    else:
        faces = [_Face(v1, v3, v2),
                 _Face(v1, v2, v4), _Face(v2, v3, v4), _Face(v3, v1, v4)]

    # 残りの頂点を各面に分配
    _divide_outer_verts(faces, verts, eps)

    # edge_faces作成
    edge_faces = defaultdict(list)
    for face in faces:
        for ekey in face.edge_keys:
            edge_faces[ekey].append(face)

    while True:
        added = False
        for i in range(len(faces)):
            try:
                face = faces[i]
            except:
                break
            if not face.outer_verts:
                continue

            v1 = max(face.outer_verts, key=lambda v: face.distance(v.co))
            if face.distance(v1.co) > eps:
                # 凸包になるようにv1から放射状に面を貼る
                added = True

                # 隠れて不要となる面を求める
                remove_faces = set()
                _find_remove_faces_re(remove_faces, v1.co, face, edge_faces,
                                      eps)

                # remove_facesを多面体から除去して穴を開ける
                for f in remove_faces:
                    for ekey in f.edge_keys:
                        edge_faces[ekey].remove(f)
                    faces.remove(f)

                # 穴に面を貼る
                new_faces = []
                ekey_count = defaultdict(int)
                for f in remove_faces:
                    for ekey in f.edge_keys:
                        ekey_count[ekey] += 1
                for ekey, cnt in ekey_count.items():
                    if cnt != 1:
                        continue
                    linkface = edge_faces[ekey][0]
                    v2, v3 = ekey
                    if linkface.verts[linkface.verts.index(v2) - 1] != v3:
                        v2, v3 = v3, v2
                    new_face = _Face(v1, v2, v3)
                    for key in new_face.edge_keys:
                        edge_faces[key].append(new_face)
                    new_faces.append(new_face)
                faces.extend(new_faces)

                # 頂点の再分配
                outer_verts = reduce(lambda a, b: a + b,
                                     (f.outer_verts for f in remove_faces))
                if v1 in outer_verts:
                    outer_verts.remove(v1)
                _divide_outer_verts(new_faces, outer_verts, eps)

            else:
                face.outer_verts = []

        if not added:
            break

    return [[v.index for v in f.verts] for f in faces]
Пример #48
0
    def process(self):
        verts_socket, poly_socket = self.inputs
        norm_socket, norm_abs_socket, origins_socket, centers_socket = self.outputs

        if not any([s.is_linked for s in self.outputs]):
            return

        if not (verts_socket.is_linked and poly_socket.is_linked):
            return

        pols_ = poly_socket.sv_get()
        vers_tupls = verts_socket.sv_get()
        vers_vects = Vector_generate(vers_tupls)
        
        # make mesh temp утилитарно - удалить в конце
        mat_collect = []
        normals_out = []
        origins = []
        norm_abs_out = []
        for verst, versv, pols in zip(vers_tupls, vers_vects, pols_):
            # medians в векторах
            medians = []
            normals = []
            centrs = []
            norm_abs = []
            for p in pols:
                # medians
                # it calcs middle point of opposite edges, 
                # than finds length vector between this two points
                v0 = versv[p[0]]
                v1 = versv[p[1]]
                v2 = versv[p[2]]
                lp=len(p)
                if lp >= 4:
                    l = ((lp-2)//2) + 2
                    v3 = versv[p[l]]
                    poi_2 = (v2+v3)/2
                    # normals
                    norm = geometry.normal(v0, v1, v2, v3)
                    normals.append(norm)
                else:
                    poi_2 = v2
                    # normals
                    norm = geometry.normal(v0, v1, v2)
                    normals.append(norm)
                poi_1 = (v0+v1)/2
                vm = poi_2 - poi_1
                medians.append(vm)
                # centrs
                x,y,z = zip(*[verst[poi] for poi in p])
                x,y,z = sum(x)/len(x), sum(y)/len(y), sum(z)/len(z)
                current_center = Vector((x,y,z))
                centrs.append(current_center)
                # normal absolute !!!
                # это совершенно нормально!!! ;-)
                norm_abs.append(current_center+norm)
                
            if self.Separate:
                norm_abs_out.append(norm_abs)    
                origins.append(centrs)
                normals_out.append(normals)
            else:
                norm_abs_out.extend(norm_abs)    
                origins.extend(centrs)
                normals_out.extend(normals)
            mat_collect_ = []
            for cen, med, nor in zip(centrs, medians, normals):
                loc = Matrix.Translation(cen)
                # need better solution for Z,Y vectors + may be X vector correction
                vecz = Vector((0, 1e-6, 1))
                q_rot0 = vecz.rotation_difference(nor).to_matrix().to_4x4()
                q_rot2 = nor.rotation_difference(vecz).to_matrix().to_4x4()
                if med[1]>med[0]:
                    vecy = Vector((1e-6, 1, 0)) * q_rot2
                else:
                    vecy = Vector((1, 1e-6, 0)) * q_rot2
                q_rot1 = vecy.rotation_difference(med).to_matrix().to_4x4()
                # loc is matrix * rot vector * rot vector
                M = loc*q_rot1*q_rot0
                lM = [ j[:] for j in M ]
                mat_collect_.append(lM)
            mat_collect.extend(mat_collect_)

        
        if not self.Separate:
            norm_abs_out = [norm_abs_out]
            origins = [origins]
            normals_out = [normals_out]

        centers_socket.sv_set(mat_collect)
        norm_abs_socket.sv_set(Vector_degenerate(norm_abs_out))
        origins_socket.sv_set(Vector_degenerate(origins))
        norm_socket.sv_set(Vector_degenerate(normals_out))
Пример #49
0
 def normal(self):
     return geometry.normal(*[x._position for x in self._vertices])
Пример #50
0
def offset_edges(verts_in, edges_in, shift_in):
    # take an input mesh (verts + edges ) and an offset property and generate the resulting geometry

    verts_out = []
    faces_out = []
    
    verts_z = verts_in[:]
    verts_in = [Vector(v).to_2d() for v in verts_in]

    diff_shift = len(verts_in) - len(shift_in)
    if diff_shift >= 0:
        shift_in.extend([shift_in[-1] for _ in range(diff_shift)])
    else:
        shift_in = shift_in[:diff_shift]
    
    #Searching neighbours for each point
    neighbours = [[] for _ in verts_in]
    for edg in edges_in:
        neighbours[edg[0]].append(edg)
        neighbours[edg[1]].append(edg)

    #Sorting neighbours by hour hand
    for i, p_neighbs in enumerate(neighbours):
        if len(p_neighbs) != 1:
            angles = [0]
            first_item = list(set(p_neighbs[0]) - set([i]))[0]
            for another_neighb in p_neighbs[1:]:            
                second_item = list(set(another_neighb) - set([i]))[0]
                vector1 = verts_in[first_item] - verts_in[i]
                vector2 = verts_in[second_item] - verts_in[i]
                angles.append(calc_angle(vector1, vector2))
            sorted_ = list(zip(angles, p_neighbs))
            sorted_.sort()
            neighbours[i] = [e[1] for e in sorted_]
            
    def get_end_points(item_point, shift):
        second_item = list(set(neighbours[item_point][0]) - set([item_point]))[0]
        vert_edg = verts_in[item_point] - verts_in[second_item]
        mat_r1 = Matrix.Rotation(radians(-45),2,'X')
        mat_r2 = Matrix.Rotation(radians(45),2,'X')
        shift_end_points = shift/sin(radians(45))
        vert_new1 = (vert_edg * mat_r1).normalized() * shift_end_points + verts_in[item_point]
        vert_new2 = (vert_edg * mat_r2).normalized() * shift_end_points + verts_in[item_point]
        return [vert_new1,vert_new2]

    def get_middle_points(item_point, shift):
        points = []
        for i in range(len(neighbours[item_point])):
            current_edges = (neighbours[item_point][i:] + neighbours[item_point][:i])[:2]
            second_item1 = list(set(current_edges[0]) - set([item_point]))[0]
            second_item2 = list(set(current_edges[1]) - set([item_point]))[0]
            vert_edg1 = verts_in[second_item1] - verts_in[item_point]
            vert_edg2 = verts_in[second_item2] - verts_in[item_point]
            angle = calc_angle(vert_edg1, vert_edg2) / 2
            mat_r = Matrix.Rotation(angle, 2, 'X')        
            points.append((vert_edg1 * mat_r).normalized() * shift/sin(angle) + verts_in[item_point])
        return points

    #Seting points
    findex_new_points = [0]
    for i,sh in enumerate(shift_in):
        #avoid zero offset
        if not sh:
            sh = 0.001
        
        if len(neighbours[i]) == 1:
            verts_out.extend(get_end_points(i,sh))
            findex_new_points.append(findex_new_points[-1] + 2)
        else:
            p = get_middle_points(i,sh)
            verts_out.extend(p)
            findex_new_points.append(findex_new_points[-1] + len(p))
        
    # Preparing Z coordinate
    z_co = []
    for c,(i1,i2) in enumerate(zip(findex_new_points[:-1], findex_new_points[1:])):
        z_co.extend([verts_z[c][2] for _ in range(i2-i1)])
        
    #Creating faces and mark outer edges and central points
    outer_edges = []
    current_index = len(verts_out) - 1
    vers_mask = [0 for _ in verts_out]
    nomber_outer_points = current_index
    position_old_points = [0 for _ in verts_out]
    for edg in edges_in:
        need_points = []
        for i in edg:
            if len(neighbours[i]) <= 2:
                need_points.extend([findex_new_points[i], findex_new_points[i] + 1])
            else:
                position = neighbours[i].index(edg)
                nomber_points = len(neighbours[i])
                variants_positions = list(range(findex_new_points[i], findex_new_points[i] + nomber_points))
                need_points.extend((variants_positions[position - 1:] + variants_positions[:position - 1])[:2])
    
        vec_edg = verts_in[edg[0]] - verts_in[edg[1]]
        vec_1 = verts_out[need_points[0]] - verts_in[edg[0]]
        vec_2 = verts_out[need_points[1]] - verts_in[edg[0]]
        vec_3 = verts_out[need_points[2]] - verts_in[edg[1]]
        vec_4 = verts_out[need_points[3]] - verts_in[edg[1]]
        new_vecs = [vec_1, vec_2, vec_3, vec_4]

        angles = [vec_edg.angle_signed(vec) for vec in new_vecs]

        if position_old_points[edg[0]] == 0:
            verts_out.append(verts_in[edg[0]])
            z_co.append(verts_z[edg[0]][2]) 
            vers_mask.append(1)
            current_index += 1
            position_old_points[edg[0]] = current_index
    
        if position_old_points[edg[1]] == 0:
            verts_out.append(verts_in[edg[1]])
            z_co.append(verts_z[edg[1]][2])
            vers_mask.append(1)
            current_index += 1
            position_old_points[edg[1]] = current_index
            
        n_p = need_points
        if angles[0] < 0 and angles[2] < 0 or angles[0] >= 0 and angles[2] >= 0:
            new_edges = [[n_p[1], position_old_points[edg[0]], position_old_points[edg[1]], n_p[3]],
                         [n_p[0], position_old_points[edg[0]], position_old_points[edg[1]], n_p[2]]]
                             
            outer_edges.extend([[n_p[1],n_p[3]],[n_p[0],n_p[2]]])
        else:
            new_edges = [[n_p[0], position_old_points[edg[0]], position_old_points[edg[1]], n_p[3]],
                         [n_p[1], position_old_points[edg[0]], position_old_points[edg[1]], n_p[2]]]
                         
            outer_edges.extend([[n_p[0],n_p[3]],[n_p[1],n_p[2]]])

        if len(neighbours[edg[0]]) == 1:
            new_edges.append([need_points[1], position_old_points[edg[0]], need_points[0]])
            outer_edges.append([need_points[1],need_points[0]])
        if len(neighbours[edg[1]]) == 1:
            new_edges.append([need_points[2], position_old_points[edg[1]], need_points[3]])
            outer_edges.append([need_points[2],need_points[3]])
    
        for c,face in enumerate(new_edges):
            if normal(*[verts_out[i].to_3d() for i in face])[2] < 0:
                new_edges[c] = new_edges[c][::-1]
        
        faces_out.extend(new_edges)

    verts_out = [(v.x, v.y, z) for v, z in zip(verts_out, z_co)]
    return verts_out, faces_out, outer_edges, vers_mask
Пример #51
0
def OBB(vecs, r_indices=None, eps=1e-6):
    """Convex hull を用いたOBBを返す。
    Z->Y->Xの順で長さが最少となる軸を求める。
    :param vecs: list of Vector
    :type vecs: list | tuple
    :param r_indices: listを渡すとconvexhullの結果を格納する
    :type r_indices: None | list
    :param eps: 種々の計算の閾値
    :return:
        (matrix, obb_size)
        matrix:
            type: Matrx
            OBBの回転と中心を表す。vecsが二次元ベクトルの場合は3x3, 三次元なら4x4。
        obb_size:
            type: Vector
            OBBの各軸の長さ。vecsと同じ次元。
    :rtype: (Matrix, Vector)
    """

    if not vecs:
        return None, None

    # 2D ----------------------------------------------------------------------
    if len(vecs[0]) == 2:
        mat = Matrix.Identity(3)
        bb_size = Vector((0, 0))

        indices = convex_hull_2d(vecs, eps)
        if r_indices:
            r_indices[:] = indices

        if len(indices) == 1:
            mat.col[2][:2] = vecs[0]
        elif len(indices) == 2:
            v1 = vecs[indices[0]]
            v2 = vecs[indices[1]]
            xaxis = (v2 - v1).normalized()
            angle = math.atan2(xaxis[1], xaxis[0])
            mat2 = Matrix.Rotation(angle, 2)
            mat.col[0][:2] = mat2.col[0]
            mat.col[1][:2] = mat2.col[1]
            mat.col[2][:2] = (v1 + v2) / 2
            bb_size[0] = (v2 - v1).length
        else:
            yaxis = _closest_axis_on_plane(vecs, indices)
            angle = math.atan2(yaxis[1], yaxis[0]) - math.pi / 2  # X軸
            mat2 = Matrix.Rotation(angle, 2)
            imat2 = Matrix.Rotation(-angle, 2)
            rotvecs = [imat2 * v for v in vecs]
            loc = Vector((0, 0))
            for i in range(2):
                rotvecs.sort(key=lambda v: v[i])
                bb_size[i] = rotvecs[-1][i] - rotvecs[0][i]
                loc[i] = (rotvecs[0][i] + rotvecs[-1][i]) / 2
            mat.col[0][:2] = mat2.col[0]
            mat.col[1][:2] = mat2.col[1]
            mat.col[2][:2] = mat2 * loc
        return mat, bb_size

    # 3D ----------------------------------------------------------------------
    mat = Matrix.Identity(4)
    bb_size = Vector((0, 0, 0))

    indices = convex_hull(vecs, eps)

    if r_indices:
        r_indices[:] = indices

    if isinstance(indices[0], int):  # 2d
        if len(indices) == 1:
            mat.col[3][:3] = vecs[0]
            return mat, bb_size
        
        elif len(indices) == 2:
            # 同一線上
            v1 = vecs[indices[0]]
            v2 = vecs[indices[1]]
            xaxis = (v2 - v1).normalized()
            quat = Vector((1, 0, 0)).rotation_difference(xaxis)
            mat = quat.to_matrix().to_4x4()
            mat.col[3][:3] = (v1 + v2) / 2
            bb_size[0] = (v2 - v1).length
            return mat, bb_size

        else:
            # 同一平面上
            medium = reduce(lambda a, b: a + b, vecs) / len(vecs)
            v1 = max(vecs, key=lambda v: (v - medium).length)
            v2 = max(vecs, key=lambda v: (v - v1).length)
            line = v2 - v1
            v3 = max(vecs, key=lambda v: line.cross(v - v1).length)
            zaxis = geom.normal(v1, v2, v3)
            if zaxis[2] < 0.0:
                zaxis.negate()

            quat = zaxis.rotation_difference(Vector((0, 0, 1)))
            rotvecs = [quat * v for v in vecs]
            indices_2d = indices

    else:  # 3d
        indices_set = set(chain(*indices))
        zaxis = None
        dist = 0.0
        # 最も距離の近い面(平面)と頂点を求める
        for tri in indices:
            v1, v2, v3 = [vecs[i] for i in tri]
            normal = geom.normal(v1, v2, v3)
            d = 0.0
            for v4 in (vecs[i] for i in indices_set if i not in tri):
                f = abs(geom.distance_point_to_plane(v4, v1, normal))
                d = max(f, d)
            if zaxis is None or d < dist:
                zaxis = -normal
                dist = d

        quat = zaxis.rotation_difference(Vector((0, 0, 1)))
        rotvecs = [(quat * v).to_2d() for v in vecs]
        indices_2d = convex_hull_2d(rotvecs, eps)

    yaxis = _closest_axis_on_plane(rotvecs, indices_2d)
    yaxis = quat.inverted() * yaxis.to_3d()

    xaxis = yaxis.cross(zaxis)
    xaxis.normalize()  # 不要?

    mat.col[0][:3] = xaxis
    mat.col[1][:3] = yaxis
    mat.col[2][:3] = zaxis

    # OBBの大きさと中心を求める
    imat = mat.inverted()
    rotvecs = [imat * v for v in vecs]
    loc = Vector()
    for i in range(3):
        rotvecs.sort(key=lambda v: v[i])
        bb_size[i] = rotvecs[-1][i] - rotvecs[0][i]
        loc[i] = (rotvecs[0][i] + rotvecs[-1][i]) / 2
    mat.col[3][:3] = mat * loc
    return mat, bb_size
Пример #52
0
 def calc_normal(self):
     return geom.normal(*self.coords)
Пример #53
0
 def execute(self, context):
     nor = normal(p.co for p in self.points[:3])
     co = Vector(self.points[-1].co) + nor * self.offset
     bpy.ops.mesh.bisect(plane_co=co, plane_no=nor, use_fill=self.use_fill, clear_inner=self.clear_inner, clear_outer=self.clear_outer)
     return {'FINISHED'}
def offset_edges(verts_in, edges_in, shift_in):
    # take an input mesh (verts + edges ) and an offset property and generate the resulting geometry

    verts_out = []
    faces_out = []
    
    verts_z = verts_in[:]
    verts_in = [Vector(v).to_2d() for v in verts_in]

    diff_shift = len(verts_in) - len(shift_in)
    if diff_shift >= 0:
        shift_in.extend([shift_in[-1] for _ in range(diff_shift)])
    else:
        shift_in = shift_in[:diff_shift]
    
    #Searching neighbours for each point
    neighbours = [[] for _ in verts_in]
    for edg in edges_in:
        neighbours[edg[0]].append(edg)
        neighbours[edg[1]].append(edg)

    #Sorting neighbours by hour hand
    for i, p_neighbs in enumerate(neighbours):
        if len(p_neighbs) != 1:
            angles = [0]
            first_item = list(set(p_neighbs[0]) - set([i]))[0]
            for another_neighb in p_neighbs[1:]:            
                second_item = list(set(another_neighb) - set([i]))[0]
                vector1 = verts_in[first_item] - verts_in[i]
                vector2 = verts_in[second_item] - verts_in[i]
                angles.append(calc_angle(vector1, vector2))
            sorted_ = list(zip(angles, p_neighbs))
            sorted_.sort()
            neighbours[i] = [e[1] for e in sorted_]
            
    def get_end_points(item_point, shift):
        second_item = list(set(neighbours[item_point][0]) - set([item_point]))[0]
        vert_edg = verts_in[item_point] - verts_in[second_item]
        mat_r1 = Matrix.Rotation(radians(-45),2,'X')
        mat_r2 = Matrix.Rotation(radians(45),2,'X')
        shift_end_points = shift/sin(radians(45))
        vert_new1 = (vert_edg @ mat_r1).normalized() * shift_end_points + verts_in[item_point]
        vert_new2 = (vert_edg @ mat_r2).normalized() * shift_end_points + verts_in[item_point]
        return [vert_new1,vert_new2]

    def get_middle_points(item_point, shift):
        points = []
        for i in range(len(neighbours[item_point])):
            current_edges = (neighbours[item_point][i:] + neighbours[item_point][:i])[:2]
            second_item1 = list(set(current_edges[0]) - set([item_point]))[0]
            second_item2 = list(set(current_edges[1]) - set([item_point]))[0]
            vert_edg1 = verts_in[second_item1] - verts_in[item_point]
            vert_edg2 = verts_in[second_item2] - verts_in[item_point]
            angle = calc_angle(vert_edg1, vert_edg2) / 2
            mat_r = Matrix.Rotation(angle, 2, 'X')        
            points.append((vert_edg1 @ mat_r).normalized() * shift/sin(angle) + verts_in[item_point])
        return points

    #Seting points
    findex_new_points = [0]
    for i,sh in enumerate(shift_in):
        #avoid zero offset
        if not sh:
            sh = 0.001
        
        if len(neighbours[i]) == 1:
            verts_out.extend(get_end_points(i,sh))
            findex_new_points.append(findex_new_points[-1] + 2)
        else:
            p = get_middle_points(i,sh)
            verts_out.extend(p)
            findex_new_points.append(findex_new_points[-1] + len(p))
        
    # Preparing Z coordinate
    z_co = []
    for c,(i1,i2) in enumerate(zip(findex_new_points[:-1], findex_new_points[1:])):
        z_co.extend([verts_z[c][2] for _ in range(i2-i1)])
        
    #Creating faces and mark outer edges and central points
    outer_edges = []
    current_index = len(verts_out) - 1
    vers_mask = [0 for _ in verts_out]
    nomber_outer_points = current_index
    position_old_points = [0 for _ in verts_out]
    for edg in edges_in:
        need_points = []
        for i in edg:
            if len(neighbours[i]) <= 2:
                need_points.extend([findex_new_points[i], findex_new_points[i] + 1])
            else:
                position = neighbours[i].index(edg)
                nomber_points = len(neighbours[i])
                variants_positions = list(range(findex_new_points[i], findex_new_points[i] + nomber_points))
                need_points.extend((variants_positions[position - 1:] + variants_positions[:position - 1])[:2])
    
        vec_edg = verts_in[edg[0]] - verts_in[edg[1]]
        vec_1 = verts_out[need_points[0]] - verts_in[edg[0]]
        vec_2 = verts_out[need_points[1]] - verts_in[edg[0]]
        vec_3 = verts_out[need_points[2]] - verts_in[edg[1]]
        vec_4 = verts_out[need_points[3]] - verts_in[edg[1]]
        new_vecs = [vec_1, vec_2, vec_3, vec_4]

        angles = [vec_edg.angle_signed(vec) for vec in new_vecs]

        if position_old_points[edg[0]] == 0:
            verts_out.append(verts_in[edg[0]])
            z_co.append(verts_z[edg[0]][2]) 
            vers_mask.append(1)
            current_index += 1
            position_old_points[edg[0]] = current_index
    
        if position_old_points[edg[1]] == 0:
            verts_out.append(verts_in[edg[1]])
            z_co.append(verts_z[edg[1]][2])
            vers_mask.append(1)
            current_index += 1
            position_old_points[edg[1]] = current_index
            
        n_p = need_points
        if angles[0] < 0 and angles[2] < 0 or angles[0] >= 0 and angles[2] >= 0:
            new_edges = [[n_p[1], position_old_points[edg[0]], position_old_points[edg[1]], n_p[3]],
                         [n_p[0], position_old_points[edg[0]], position_old_points[edg[1]], n_p[2]]]
                             
            outer_edges.extend([[n_p[1],n_p[3]],[n_p[0],n_p[2]]])
        else:
            new_edges = [[n_p[0], position_old_points[edg[0]], position_old_points[edg[1]], n_p[3]],
                         [n_p[1], position_old_points[edg[0]], position_old_points[edg[1]], n_p[2]]]
                         
            outer_edges.extend([[n_p[0],n_p[3]],[n_p[1],n_p[2]]])

        if len(neighbours[edg[0]]) == 1:
            new_edges.append([need_points[1], position_old_points[edg[0]], need_points[0]])
            outer_edges.append([need_points[1],need_points[0]])
        if len(neighbours[edg[1]]) == 1:
            new_edges.append([need_points[2], position_old_points[edg[1]], need_points[3]])
            outer_edges.append([need_points[2],need_points[3]])
    
        for c,face in enumerate(new_edges):
            if normal(*[verts_out[i].to_3d() for i in face])[2] < 0:
                new_edges[c] = new_edges[c][::-1]
        
        faces_out.extend(new_edges)

    verts_out = [(v.x, v.y, z) for v, z in zip(verts_out, z_co)]
    return verts_out, faces_out, outer_edges, vers_mask
    def execute(self, context):
        if self.mode in ('selected', 'center', 'grid', 'active'):
            self.execute_builtin(context)
            return {'FINISHED'}
        
        actob = context.active_object
        mat = actob.matrix_world
        editmode = 'EDIT' in context.mode
        if editmode:
            bpy.ops.object.mode_set(mode='OBJECT')
        
        mesh = None
        if editmode and actob.type == 'MESH':
            mesh = actob.data
        
        loc = None
        if self.mode == 'circle':
            if mesh:
                vecs = (v.co for v in mesh.vertices if v.select and not v.hide)
                vecs = [mat * v for v in vecs]
            else:
                vecs = [Vector(ob.matrix_world.col[3][:3])
                        for ob in context.selected_objects]
            if len(vecs) == 3:
                center = vam.center_of_circumscribed_circle_tri(*vecs)
                if center:
                    loc = center
                    r = (vecs[0] - loc).length
                    self.report({'INFO'}, 'r: {}'.format(r))
            else:
                self.report({'WARNING'}, 'Select 3 vectors')

        elif self.mode == 'sphere':
            if mesh:
                vecs = (v.co for v in mesh.vertices if v.select and not v.hide)
                vecs = [mat * v for v in vecs]
                if len(vecs) < 4:
                    self.report({'WARNING'}, 'Select more than 4 vertices')
                elif len(vecs) > 16:
                    # 計算に時間がかかるのでパス。
                    txt = '{} vertices is selected. Too many'.format(len(vecs))
                    self.report({'WARNING'}, txt)
                else:
                    locations = []
                    normals = []
                    for v1, v2, v3 in combinations(vecs, 3):
                        center = vam.center_of_circumscribed_circle_tri(
                                         v1, v2, v3)
                        if center:
                            locations.append(center)
                            normals.append(geom.normal(v1, v2, v3))
                    inters = []
                    for i, j in combinations(range(len(locations)), 2):
                        cross_length = normals[i].cross(normals[j]).length
                        angle = math.asin(min(cross_length, 1.0))
                        if angle < ANGLE_THRESHOLD:
                            continue
                        v1 = locations[i]
                        v2 = v1 + normals[i]
                        v3 = locations[j]
                        v4 = v3 + normals[j]
                        inter = geom.intersect_line_line(v1, v2, v3, v4)
                        if inter:
                            inters.append((inter[0] + inter[1]) / 2)
                    if inters:
                        loc = (reduce(lambda v1, v2: v1 + v2, inters) /
                               len(inters))
                        r_sum = 0
                        for v in vecs:
                            r_sum += (v - loc).length
                        r = r_sum /len(vecs)
                        self.report({'INFO'}, 'r: {}'.format(r))
                
        elif self.mode == 'median':
            if mesh:
                dm = self.get_dm(context)
                vecs = [v.co for v in dm.vertices if v.select and not v.hide]
                if vecs:
                    vecs = [mat * v for v in vecs]
                    loc = (reduce(lambda v1, v2: v1 + v2, vecs) /
                                       len(vecs))
        
        elif self.mode == 'boundbox':
            if mesh:
                dm = self.get_dm(context)
                vecs = (v.co for v in dm.vertices if v.select and not v.hide)
                vecs = [mat * v for v in vecs]
                if vecs:
                    v = vecs[0]
                    mins = [v[0], v[1], v[2]]
                    maxs = [v[0], v[1], v[2]]
                    for v in vecs:
                        for i in range(3):
                            if v[i] < mins[i]:
                                mins[i] = v[i]
                            if v[i] > maxs[i]:
                                maxs[i] = v[i]
                    loc = Vector([(mins[i] + maxs[i]) / 2 for i in range(3)])
        
        if editmode:
            bpy.ops.object.mode_set(mode='EDIT')

        if loc:
            context.scene.cursor_location = loc

        return {'FINISHED'}