Example #1
0
def stroke_normal(it):
    """
    Compute the 2D normal at the stroke vertex pointed by the iterator
    'it'.  It is noted that Normal2DF0D computes normals based on
    underlying FEdges instead, which is inappropriate for strokes when
    they have already been modified by stroke geometry modifiers.
    """
    # first stroke segment
    it_next = it.incremented()
    if it.is_begin:
        e = it_next.object.point_2d - it.object.point_2d
        n = Vector((e[1], -e[0]))
        return n.normalized()
    # last stroke segment
    it_prev = it.decremented()
    if it_next.is_end:
        e = it.object.point_2d - it_prev.object.point_2d
        n = Vector((e[1], -e[0]))
        return n.normalized()
    # two subsequent stroke segments
    e1 = it_next.object.point_2d - it.object.point_2d
    e2 = it.object.point_2d - it_prev.object.point_2d
    n1 = Vector((e1[1], -e1[0])).normalized()
    n2 = Vector((e2[1], -e2[0])).normalized()
    n = (n1 + n2)
    return n.normalized()
Example #2
0
def _do_rgb_to_dxyz_w_calc(prototype, data):
    r = data
    _set_xyz(prototype, r, r[prototype.index("R"):prototype.index("B")])
    dir_vec = Vector((_get_xyz(prototype, r)))
    _set_width(prototype, r, 1 - dir_vec.magnitude)
    _set_xyz(prototype, r, dir_vec.normalized())
    _set_rgb(prototype, r, [1, 1, 1])
 def execute(self, context):
     volmesh = context.active_object
     for i in range(len(volmesh.custom_vectorfield)):
         tempVect = Vector(volmesh.custom_vectorfield[i].vvelocity)
         volmesh.custom_vectorfield[i].vvelocity = tempVect.normalized()
     context.window_manager.vf_showingvelocitylines = -1
     return {'FINISHED'}
Example #4
0
def get_dim_coords(context, myobj, DimGen, dim, mat, offset_pos = True):
    dimProps = dim
    if dim.uses_style:
        for alignedDimStyle in context.scene.StyleGenerator.alignedDimensions:
            if alignedDimStyle.name == dim.style:
                dimProps = alignedDimStyle

    # get points positions from indicies
    aMatrix = dim.dimObjectA.matrix_world
    bMatrix = dim.dimObjectB.matrix_world

    offset = dim.dimOffset
    geoOffset = dim.dimLeaderOffset

    # get points positions from indicies
    p1Local = None
    p2Local = None

    try:
        p1Local = get_mesh_vertex(dim.dimObjectA,dim.dimPointA,dimProps.evalMods)
    except IndexError:
        print('p1 excepted for ' + dim.name + ' on ' + myobj.name)

    try:
        p2Local = get_mesh_vertex(dim.dimObjectB,dim.dimPointB,dimProps.evalMods)
    except IndexError:
        print('p2 excepted for ' + dim.name + ' on ' + myobj.name)

    p1 = get_point(p1Local, dim.dimObjectA,aMatrix)
    p2 = get_point(p2Local, dim.dimObjectB,bMatrix)
        
    #check dominant Axis
    sortedPoints = sortPoints(p1, p2)
    p1 = sortedPoints[0]
    p2 = sortedPoints[1]

    distVector = Vector(p1)-Vector(p2)
    dist = distVector.length
    midpoint = interpolate3d(p1, p2, fabs(dist / 2))
    normDistVector = distVector.normalized()


    # Compute offset vector from face normal and user input
    rotationMatrix = Matrix.Rotation(dim.dimRotation, 4, normDistVector)
    selectedNormal = Vector(select_normal(myobj, dim, normDistVector, midpoint, dimProps))
    
    userOffsetVector = rotationMatrix@selectedNormal
    offsetDistance = userOffsetVector*offset
    geoOffsetDistance = offsetDistance.normalized()*geoOffset

    if offsetDistance < geoOffsetDistance:
        offsetDistance = geoOffsetDistance

    dimLineStart = Vector(p1)+offsetDistance
    dimLineEnd = Vector(p2)+offsetDistance
    
    if offset_pos:
        return [dimLineStart,dimLineEnd]
    else:
        return [p1,p2]
Example #5
0
    def _pre_calc(self):
        curve = self.curve
        t_min, t_max = curve.get_u_bounds()
        ts = np.linspace(t_min, t_max, num=self.resolution)

        points = curve.evaluate_array(ts)
        tangents, normals, binormals = curve.tangent_normal_binormal_array(ts)
        tangents /= np.linalg.norm(tangents, axis=1, keepdims=True)

        normal = normals[0]
        if np.linalg.norm(normal) > 1e-4:
            binormal = binormals[0]
            binormal /= np.linalg.norm(binormal)
        else:
            tangent = tangents[0]
            normal = Vector(tangent).orthogonal()
            normal = np.array(normal)
            binormal = np.cross(tangent, normal)
            binormal /= np.linalg.norm(binormal)

        out_normals = [normal]
        out_binormals = [binormal]

        for point, tangent in zip(points[1:], tangents[1:]):
            plane = PlaneEquation.from_normal_and_point(Vector(tangent), Vector(point))
            normal = plane.projection_of_vector(Vector(point), Vector(point + normal))
            normal = np.array(normal.normalized())
            binormal = np.cross(tangent, normal)
            binormal /= np.linalg.norm(binormal)
            out_normals.append(normal)
            out_binormals.append(binormal)

        self.quats = self._make_quats(points, tangents, np.array(out_normals), np.array(out_binormals))
        self.tknots = ts
Example #6
0
 def getVector(self, point):
     vect = Vector((0.0, 0.0, 0.0))
     for n in range(0, len(self.guides)):
         guide = self.guides[n]
         weight = self.weights[n]
         vect += guide.getVector(point).normalized() * weight
     return vect.normalized()
def create_spiral_meshdata(center=(0, 0, 0),
                           offset=1,
                           points_per_round=20,
                           rounds=3,
                           extend=0,
                           invert_direction=False):

    verts = []
    for i in range(points_per_round * rounds + 1):
        p = i / points_per_round
        t = 2 * math.pi * p
        r = offset * p  #+ p
        verts.append(
            Vector((r * math.sin(t) + center[0], r * math.cos(t) + center[1],
                    center[2])))

    if extend > 0:
        tangent = Vector((r * math.cos(t), -r * math.sin(t), 0.0))
        verts.append(
            Vector(verts[len(verts) - 1]) + extend * tangent.normalized())

    if invert_direction:
        for i, v in enumerate(verts):
            verts[i] = verts[i] - verts[len(verts) - 1]
        verts.reverse()

    edges = []
    for i in range(len(verts) - 1):
        edges.append([i, i + 1])

    mesh_data = bpy.data.meshes.new("spiral")
    mesh_data.from_pydata(verts, edges, [])

    return mesh_data, verts[0], verts[len(verts) - 1]
Example #8
0
 def create_power_labels(self):
     obj = bpy.context.scene.objects.get(self.PowerShowObject)
     self.create_total_labels()
     mat_world = obj.matrix_world
     cam = bpy.context.scene.objects['Camera']
     cam_center = cam.location
     for poly in obj.data.polygons:
         text_name = 'sun_' + obj.name + '_text_' + str(poly.index).replace(
             '.', '_')
         bpy.ops.object.text_add(location=mat_world * Vector(poly.center))
         myFontOb = bpy.context.object
         myFontOb.data.body = "0"
         myFontOb.name = text_name
         myFontOb.data.align = 'CENTER'
         myFontOb.scale = (0.3, 0.3, 0.3)
         obj.rotation_mode = 'QUATERNION'
         cam_norm = obj.rotation_quaternion * poly.normal
         fnorm = Vector((-1, 0, 0))
         axis = fnorm.cross(cam_norm)
         dot = fnorm.normalized().dot(cam_norm.normalized())
         dot = clamp(dot, -1.0, 1.0)
         if axis.length < 1.0e-8:
             axis = Vector(get_ortho(fnorm.x, fnorm.y, fnorm.z))
         myFontOb.rotation_mode = 'AXIS_ANGLE'
         myFontOb.rotation_axis_angle = [
             math.acos(dot) + math.pi, axis[0], axis[1], axis[2]
         ]
         myFontOb.convert_space(from_space='WORLD', to_space='LOCAL')
         myFontOb.rotation_mode = 'XYZ'
         myFontOb.rotation_euler = (radians(90), 0,
                                    myFontOb.rotation_euler[2] +
                                    radians(90))
         bpy.context.scene.update()
         self.PowerObjectLabels_created = True
Example #9
0
def JoinAxis(VX=0, VY=0, VZ=0):
	vec = Vector([VX, VY, VZ])

	CLIP = ClipAxis(vec.length)
	NORM = vec.normalized()*CLIP

	return NORM
Example #10
0
 def proj_z(self, t, dz0, next=None, dz1=0):
     """
         length of projection along crossing line / circle
         deformation unit vector for profil in z axis at line / line intersection
         so f(y) = position of point in yz plane
     """
     return Vector((0, 1)), 1
     """
         NOTE (to myself):
           In theory this is how it has to be done so sections follow path,
           but in real world results are better when sections are z-up.
           So return a dumb 1 so f(y) = y
     """
     if next is None:
         dz = dz0 / self.length
     else:
         dz = (dz1 + dz0) / (self.length + next.length)
     return Vector((0, 1)), sqrt(1 + dz * dz)
     # 1 / sqrt(1 + (dz0 / self.length) * (dz0 / self.length))
     if next is None:
         return Vector((-dz0, self.length)).normalized(), 1
     v0 = Vector((self.length, dz0))
     v1 = Vector((next.length, dz1))
     direction = Vector((-dz0, self.length)).normalized() + Vector((-dz1, next.length)).normalized()
     adj = v0 * v1
     hyp = (v0.length * v1.length)
     c = min(1, max(-1, adj / hyp))
     size = -cos(pi - 0.5 * acos(c))
     return direction.normalized(), size
 def add_torus(self, majSeg, minSeg, majRad, minRad):
     lv = []
     circ = math.pi*2
     majCirc = circ/majSeg
     minCirc = circ/minSeg
     index = 0
     rings = []
     for maj in range(majSeg):
         majTheta = majCirc*maj
         dx = math.cos(majTheta) * majRad
         dy = math.sin(majTheta) * majRad
         n = Vector((dx, dy, 0))
         minorRing = []
         for min in range(minSeg):
             minTheta = minCirc*min
             dn = math.cos(minTheta) * minRad
             dz = math.sin(minTheta) * minRad
             co = n + n.normalized() * dn + Vector((0, 0, dz))
             co = co.to_tuple()
             lv.append(self.new_vertex((Vector((co)))))
             minorRing.append(index)
             index += 1
         rings.append(minorRing)
     for ri in range(len(rings)-1):
         ring = rings[ri]
         nextRing = rings[ri+1]
         for i in range(len(ring)-1):
             self.new_face([lv[ring[i]], lv[nextRing[i]], lv[nextRing[i+1]], lv[ring[i+1]]])
         self.new_face([lv[ring[0]], lv[ring[len(ring)-1]], lv[nextRing[len(nextRing)-1]], lv[nextRing[0]]])
     ring = rings[len(rings)-1]
     nextRing = rings[0]
     for i in range(len(ring)-1):
         self.new_face([lv[ring[i]], lv[nextRing[i]], lv[nextRing[i+1]], lv[ring[i+1]]])
     self.new_face([lv[ring[0]], lv[ring[len(ring)-1]], lv[nextRing[len(nextRing)-1]], lv[nextRing[0]]])
Example #12
0
def rot_axis_quat(vector1, vector2):
    """ Find the rotation (quaternion) from vector 1 to vector 2"""
    vector1 = vector1.normalized()
    vector2 = vector2.normalized()
    cosTheta = vector1.dot(vector2)
    rotationAxis = Vector((0.0, 0.0, 0.0))
    if (cosTheta < -1 + 0.001):
        v = Vector((0.0, 1.0, 0.0))
        #Get the vector at the right angles to both
        rotationAxis = vector1.cross(v)
        rotationAxis = rotationAxis.normalized()
        q = Quaternion()
        q.w = 0.0
        q.x = rotationAxis.x
        q.y = rotationAxis.y
        q.z = rotationAxis.z
    else:
        rotationAxis = vector1.cross(vector2)
        s = math.sqrt((1.0 + cosTheta) * 2.0)
        invs = 1 / s
        q = Quaternion()
        q.w = s * 0.5
        q.x = rotationAxis.x * invs
        q.y = rotationAxis.y * invs
        q.z = rotationAxis.z * invs
    return q
Example #13
0
 def proj_z(self, t, dz0, next=None, dz1=0):
     """
         length of projection along crossing line / circle
         deformation unit vector for profil in z axis at line / line intersection
         so f(y) = position of point in yz plane
     """
     return Vector((0, 1)), 1
     """
         NOTE (to myself):
           In theory this is how it has to be done so sections follow path,
           but in real world results are better when sections are z-up.
           So return a dumb 1 so f(y) = y
     """
     if next is None:
         dz = dz0 / self.length
     else:
         dz = (dz1 + dz0) / (self.length + next.length)
     return Vector((0, 1)), sqrt(1 + dz * dz)
     # 1 / sqrt(1 + (dz0 / self.length) * (dz0 / self.length))
     if next is None:
         return Vector((-dz0, self.length)).normalized(), 1
     v0 = Vector((self.length, dz0))
     v1 = Vector((next.length, dz1))
     direction = Vector((-dz0, self.length)).normalized() + Vector(
         (-dz1, next.length)).normalized()
     adj = v0 * v1
     hyp = (v0.length * v1.length)
     c = min(1, max(-1, adj / hyp))
     size = -cos(pi - 0.5 * acos(c))
     return direction.normalized(), size
Example #14
0
def get_custom_normals(bmesh_, use_edge_angle, split_angle):
    float_normals = []

    for face in bmesh_.faces:
        if not face.smooth:
            for vertex in face.verts:
                float_normals.extend(face.normal.normalized())
        else:
            for vertex in face.verts:
                v_normals = [[face.normal.normalized(), face.calc_area()]]
                for link_face in vertex.link_faces:
                    if face.index == link_face.index:
                        continue
                    if link_face.smooth:
                        if not use_edge_angle:
                            v_normals.append([link_face.normal.normalized(), link_face.calc_area()])

                        elif use_edge_angle:
                            face_angle = face.normal.normalized().dot(link_face.normal.normalized())
                            face_angle = min(1.0, max(face_angle, -1.0))
                            face_angle = math.acos(face_angle)
                            if face_angle < split_angle:
                                v_normals.append([link_face.normal.normalized(), link_face.calc_area()])

                smooth_normal = Vector()
                area_sum = 0
                for vertex_normal in v_normals:
                    area_sum += vertex_normal[1]
                for vertex_normal in v_normals:
                    if area_sum:
                        smooth_normal += vertex_normal[0] * \
                            (vertex_normal[1] / area_sum)
                float_normals.extend(smooth_normal.normalized())

    return float_normals
Example #15
0
def average_normals(normalslist):
    avg = Vector()

    for n in normalslist:
        avg += n

    return avg.normalized()
Example #16
0
    def execute(self, context):
        # FIXME: Undo is inconsistent.
        # FIXME: Would be nicer if rotate could pick some object-local axis.

        from mathutils import Vector

        print_3d = context.scene.print_3d
        face_areas = print_3d.use_alignxy_face_area

        self.context = context
        mode_orig = context.mode
        skip_invalid = []

        for obj in context.selected_objects:
            orig_loc = obj.location.copy()
            orig_scale = obj.scale.copy()

            # When in edit mode, do as the edit mode does.
            if mode_orig == 'EDIT_MESH':
                bm = bmesh.from_edit_mesh(obj.data)
                faces = [f for f in bm.faces if f.select]
            else:
                faces = [p for p in obj.data.polygons if p.select]

            if not faces:
                skip_invalid.append(obj.name)
                continue

            # Rotate object so average normal of selected faces points down.
            normal = Vector((0.0, 0.0, 0.0))
            if face_areas:
                for face in faces:
                    normal += (face.normal * face.calc_area())
            else:
                for face in faces:
                    normal += face.normal
            normal = normal.normalized()
            normal.rotate(obj.matrix_world)  # local -> world.
            offset = normal.rotation_difference(Vector((0.0, 0.0, -1.0)))
            offset = offset.to_matrix().to_4x4()
            obj.matrix_world = offset @ obj.matrix_world
            obj.scale = orig_scale
            obj.location = orig_loc

        if len(skip_invalid) > 0:
            for name in skip_invalid:
                print(
                    f"Align to XY: Skipping object {name}. No faces selected.")
            if len(skip_invalid) == 1:
                self.report(
                    {'WARNING'},
                    f"Skipping object {skip_invalid[0]}. No faces selected.")
            else:
                self.report(
                    {'WARNING'},
                    f"Skipping some objects. No faces selected. See terminal.")
        return {'FINISHED'}
Example #17
0
 def to_point(self, amplitude, coefficient, vertex, centers, direction):
     vertex = Vector(vertex)
     vectors = []
     for center in centers:
         vector = Vector(center) - vertex
         vector = self.falloff(amplitude, coefficient, vector.length) * vector.normalized()
         vectors.append(vector)
     result = get_avg_vector(vectors)
     return result.length, result.normalized()
Example #18
0
    def execute(self, context):
        scene = context.scene
        for o in scene.objects:
            o.select_set(False)

        surf = bpy.data.objects['Mask_Surface']
        surf.select_set(True)
        bpy.context.view_layer.objects.active = surf
        thickness = surf.modifiers['Thickness'].thickness
        for m in surf.modifiers:
            try:
                bpy.ops.object.modifier_apply(apply_as='DATA', modifier=m.name)
            except:
                pass
        surf.data.update()
        me = surf.data
        n_verts = len(me.vertices)
        n_half = int(n_verts / 2)
        for i in range(n_half):
            v0 = me.vertices[i]
            v1 = me.vertices[i + n_half]
            v2 = v1.co - v0.co
            v2 = Vector((v2.x, v2.y, 0))
            v1.co = v2.normalized() * thickness + v0.co

        filter = bpy.data.objects['Filter']
        filter.select_set(True)
        bpy.context.view_layer.objects.active = filter
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.object.duplicate_move()

        ob = context.object
        ob.name = 'Mask'
        for m in ob.modifiers:
            m.show_viewport = True
        for m in ob.modifiers:
            try:
                bpy.ops.object.modifier_apply(apply_as='DATA', modifier=m.name)
            except:
                ob.modifiers.remove(m)
        bpy.ops.object.location_clear(clear_delta=False)
        bpy.ops.object.rotation_clear(clear_delta=False)
        bpy.ops.view3d.view_selected()
        for o in scene.objects:
            o.hide_viewport = True
        ob.hide_viewport = False
        ob.select_set(True)
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.context.space_data.overlay.show_statvis = True
        bpy.context.scene.tool_settings.statvis.type = 'OVERHANG'
        bpy.ops.mesh.select_mode(use_extend=False,
                                 use_expand=False,
                                 type='FACE')
        bpy.ops.mesh.select_all(action='DESELECT')
        bpy.context.scene.tool_settings.use_snap = False
        return {'FINISHED'}
Example #19
0
def getTNBfromVector(v):
    v = Vector(v)
    N = v.normalized()
    B = N.cross((0, 0, -1))
    if (B.length == 0):
        B, T = Vector((1, 0, 0)), Vector((0, 1, 0))
    else:
        B.normalize()
        T = N.cross(B).normalized()

    return T, N, B
Example #20
0
 def to_point(self, amplitude, coefficient, vertex, centers, direction):
     vertex = Vector(vertex)
     n = len(centers)
     if self.point_mode == 'AVG' or n <= 1:
         vectors = []
         for center in centers:
             vector = Vector(center) - vertex
             vector = self.falloff(amplitude, coefficient,
                                   vector.length) * vector.normalized()
             vectors.append(vector)
         result = get_avg_vector(vectors)
         return result.length, result.normalized()
     else:
         kdt = KDTree(n)
         for i, center in enumerate(centers):
             kdt.insert(Vector(center), i)
         kdt.balance()
         nearest_co, nearest_idx, nearest_distance = kdt.find(vertex)
         vector = nearest_co - vertex
         coeff = self.falloff(amplitude, coefficient, nearest_distance)
         return coeff, vector.normalized()
Example #21
0
def spread_array(bm, split_edges, split_faces, max_width, prop):
    """perform spreading for array faces"""
    if prop.count == 1:
        return

    normal = split_faces[0].normal.copy()
    median = calc_faces_median(split_faces)

    right = normal.cross(VEC_DOWN)
    split_edges = sort_edges(split_edges, right)
    split_faces = sort_faces(split_faces, right)

    # -- map each split edge to its neighbouring faces
    edge_neighbour_face_map = {
        edge: [split_faces[idx], split_faces[idx + 1]]
        for idx, edge in enumerate(split_edges)
    }

    def get_all_splitface_verts(f):
        corner_verts = list(f.verts)
        split_verts = []
        for v in corner_verts:
            split_edge = [e for e in v.link_edges if e not in f.edges].pop()
            if edge_is_vertical(split_edge):
                split_verts.append(split_edge.other_vert(v))
        return corner_verts + split_verts

    # XXX Fixme if you can
    # HACK(ranjian0) Setting spread to 1.0 causes multigroup jitters
    prop.spread = clamp(prop.spread, -1, 0.9999)

    # -- spread the array faces
    for f in split_faces:
        fm = f.calc_center_median()
        vts = get_all_splitface_verts(f)

        diff = Vector((fm - median).to_tuple(3))
        spread_factor = (max_width - prop.width) * (diff.length / max_width)
        if prop.spread > 0:
            spread_factor /= prop.count - 1
        bmesh.ops.translate(bm,
                            verts=vts,
                            vec=diff.normalized() * prop.spread *
                            spread_factor)

    # -- move the split edges to the middle of their neighbour faces
    for edge in split_edges:
        neighbours = edge_neighbour_face_map[edge]
        nmedian = calc_faces_median(neighbours)

        diff = nmedian - calc_edge_median(edge)
        diff.z = 0  # XXX prevent vertical offset from influencing split edges
        bmesh.ops.translate(bm, verts=edge.verts, vec=diff)
Example #22
0
    def initialize_from_gp(self, context):
        mat = self.matrix.inverted()
        frame = get_gp_frame(context)
        seen_verts = set()
        if frame:
            for stroke in frame.strokes:
                le = len(stroke.points)
                for i in range(le - 2):
                    p0 = mat @ stroke.points[i].co
                    p1 = mat @ stroke.points[i + 1].co
                    p2 = mat @ stroke.points[i + 2].co
                    d = p0 - p1
                    d += p1 - p2

                    location, normal, index, dist = self.bvh.find_nearest(p1)
                    face = self.bm.faces[index]
                    vert = min(face.verts, key=lambda v: (v.co - p1).length_squared)
                    self.field[vert.index] = d.normalized()
                    self.weights[vert.index] = 0
                    seen_verts.add(vert)

        current_front = set()
        for vert in seen_verts:
            for edge in vert.link_edges:
                other = edge.other_vert(vert)
                if other not in seen_verts:
                    current_front.add(vert)

        while current_front:
            new_front = set()
            for vert in current_front:
                d = Vector()
                tot = 0
                for edge in vert.link_edges:
                    other = edge.other_vert(vert)
                    if other in seen_verts:
                        if not tot:
                            d = Vector(self.field[other.index])
                        else:
                            d += best_matching_vector(
                                symmetry_space(self.field[other.index], other.normal),
                                d
                            )
                        tot += 1
                    else:
                        new_front.add(other)
                        self.weights[other.index] = self.weights[vert.index] + 1
                    if tot:
                        self.field[vert.index] = d.normalized().cross(vert.normal)
            seen_verts |= current_front
            new_front -= seen_verts
            current_front = new_front
        self.weights /= self.weights.max()
Example #23
0
 def generate_one(self, v1, v2, dv):
     dv = Vector(dv)
     size = dv.length
     dv = dv.normalized()
     orth = dv.orthogonal()
     arr1 = 0.1 * size * (orth - dv)
     arr2 = 0.1 * size * (-orth - dv)
     v3 = tuple(Vector(v2) + arr1)
     v4 = tuple(Vector(v2) + arr2)
     verts = [v1, v2, v3, v4]
     edges = [[0, 1], [1, 2], [1, 3]]
     return verts, edges
Example #24
0
def orthogonalize(x: mathutils.Vector):
    w = x.normalized()
    if abs(w.x) >= abs(w.y):
        # W.x or W.z is the largest magnitude component, swap them
        invLength = 1.0 / w.xz.length
        u = mathutils.Vector((-w.z * invLength, 0.0, w.x * invLength))
    else:
        # W.y or W.z is the largest magnitude component, swap them
        invLength = 1.0 / w.yz.length
        u = mathutils.Vector((0.0, w.z * invLength, -w.y * invLength))
    v = w.cross(u)
    return u, v, w
Example #25
0
def pass_line(vecs, is_closed_line):
    line_length = 0.0
    line_data = []
    vecs_len = len(vecs)

    for i, vec in enumerate(vecs):
        #if i == vecs_len - 1 and is_closed_line is False:
            #line_data.append((vec, line_length, 0.0, None))
        #else:
        vec_area = None
        if i == vecs_len - 1:
            if is_closed_line:
                vec_area = vecs[0] - vec
            else:
                vec_area = Vector( (0.0, 0.0, 0.0) )
        else:
            vec_area = vecs[i+1] - vec

        area_length = vec_area.length

        vec_dir = None
        if i == vecs_len - 1:
            vec_dir = (vec - vecs[i-1]).normalized()
        else:
            vec_dir = vec_area.normalized()

        line_data.append((vec.copy(), line_length, area_length, vec_dir))

        line_length += area_length

    # last point line of closed curve
    if is_closed_line:
        vec_area = vecs[0] - vecs[-1]
        area_length = vec_area.length
        vec_dir = vec_area.normalized()
        line_data.append((vecs[0], line_length, 0.0, None))

    return line_data
Example #26
0
def pass_line(vecs, is_closed_line):
    line_length = 0.0
    line_data = []
    vecs_len = len(vecs)

    for i, vec in enumerate(vecs):
        #if i == vecs_len - 1 and is_closed_line is False:
        #line_data.append((vec, line_length, 0.0, None))
        #else:
        vec_area = None
        if i == vecs_len - 1:
            if is_closed_line:
                vec_area = vecs[0] - vec
            else:
                vec_area = Vector((0.0, 0.0, 0.0))
        else:
            vec_area = vecs[i + 1] - vec

        area_length = vec_area.length

        vec_dir = None
        if i == vecs_len - 1:
            vec_dir = (vec - vecs[i - 1]).normalized()
        else:
            vec_dir = vec_area.normalized()

        line_data.append((vec.copy(), line_length, area_length, vec_dir))

        line_length += area_length

    # last point line of closed curve
    if is_closed_line:
        vec_area = vecs[0] - vecs[-1]
        area_length = vec_area.length
        vec_dir = vec_area.normalized()
        line_data.append((vecs[0], line_length, 0.0, None))

    return line_data
Example #27
0
def get_frame(p, as_matrix=False):
    p = Vector(p)
    N = p.normalized()
    B = N.cross((0, 0, -1))
    if (B.length == 0):
        B, T = Vector((1, 0, 0)), Vector((0, 1, 0))
    else:
        B.normalize()
        T = N.cross(B).normalized()

    if as_matrix:
        return Matrix([T, B, N]).to_4x4().transposed()
    else:
        return T, N, B
Example #28
0
 def execute(self, context):
     if bpy.context.object.type != 'MESH':
         self.report({'WARNING'}, 'Active object must be a mesh')
         return {'CANCELLED'}
     depsgraph = context.evaluated_depsgraph_get()
     mesh = bmesh.new()
     mesh.from_object(bpy.context.object,
                      depsgraph,
                      deform=True,
                      cage=False,
                      face_normals=True)
     mesh.transform(bpy.context.object.matrix_world)
     toolpath = internal.addObject('CURVE', 'Slices Toolpath')
     pitch_axis = Vector(self.pitch_axis)
     axis = pitch_axis.normalized()
     for i in range(0, self.slice_count):
         aux_mesh = mesh.copy()
         cut_geometry = bmesh.ops.bisect_plane(
             aux_mesh,
             geom=aux_mesh.edges[:] + aux_mesh.faces[:],
             dist=0,
             plane_co=pitch_axis * i + axis * self.offset,
             plane_no=axis,
             clear_outer=False,
             clear_inner=False)['geom_cut']
         edge_pool = set(
             [e for e in cut_geometry if isinstance(e, bmesh.types.BMEdge)])
         while len(edge_pool) > 0:
             current_edge = edge_pool.pop()
             first_vertex = current_vertex = current_edge.verts[0]
             vertices = [current_vertex.co]
             follow_edge_loop = len(edge_pool) > 0
             while follow_edge_loop:
                 current_vertex = current_edge.other_vert(current_vertex)
                 vertices.append(current_vertex.co)
                 if current_vertex == first_vertex:
                     break
                 follow_edge_loop = False
                 for edge in current_vertex.link_edges:
                     if edge in edge_pool:
                         current_edge = edge
                         edge_pool.remove(current_edge)
                         follow_edge_loop = True
                         break
             current_vertex = current_edge.other_vert(current_vertex)
             vertices.append(current_vertex.co)
             internal.addPolygonSpline(toolpath, False, vertices)
         aux_mesh.free()
     mesh.free()
     return {'FINISHED'}
Example #29
0
def RT_render_scene(scene, width, height, depth, buf):
    """Main function for rendering the scene

    Parameters
    ----------
    scene : bpy.types.Scene
        The scene that will be rendered
        It stores information about the camera, lights, objects, and material
    width : int
        Width of the rendered image
    height : int
        Height of the rendered image
    depth : int
        The recursion depth of raytracing
        i.e. the number that light bounces in the scene
    buf: numpy.ndarray
        the buffer that will be populated to store the calculated color
        for each pixel
    """

    # get all the lights from the scene
    scene_lights = [o for o in scene.objects if o.type == "LIGHT"]

    # get the location and orientation of the active camera
    cam_location = scene.camera.location
    cam_orientation = scene.camera.rotation_euler

    # get camera focal length
    focal_length = scene.camera.data.lens / scene.camera.data.sensor_width
    aspect_ratio = height / width

    # iterate through all the pixels, cast a ray for each pixel
    for y in range(height):
        # get screen space coordinate for y
        screen_y = ((y - (height / 2)) / height) * aspect_ratio
        for x in range(width):
            # get screen space coordinate for x
            screen_x = (x - (width / 2)) / width
            # calculate the ray direction
            ray_dir = Vector((screen_x, screen_y, -focal_length))
            ray_dir.rotate(cam_orientation)
            ray_dir = ray_dir.normalized()
            # populate the RGB component of the buffer with ray tracing result
            buf[y, x, 0:3] = RT_trace_ray(scene, cam_location, ray_dir,
                                          scene_lights, depth)
            # populate the alpha component of the buffer
            # to make the pixel not transparent
            buf[y, x, 3] = 1
        yield y
    return buf
Example #30
0
    def to_plane(self, amplitude, coefficient, vertex, centers, direction):
        center = Vector(centers[0])
        direction = Vector(direction)
        vertex = Vector(vertex)
        dirlength = direction.length
        if dirlength <= 0:
            raise ValueError("Direction vector must have nonzero length!")

        d = -direction.dot(center)
        # distance from vertex to plane
        rho = abs(vertex.dot(direction) + d) / dirlength

        from_center = center - vertex

        # vector is either direction or negative direction
        if from_center.dot(direction) >= 0:
            vector = direction.normalized()
        else:
            # for some reason mathutil's Vector does not have .negated()
            # thankfully we do not need direction itself anymore.
            direction.negate()
            vector = direction.normalized()

        return self.falloff(amplitude, coefficient, rho), vector
Example #31
0
def _do_rgb_to_dxyz_w_calc(overload: "ParsedLightOverload") -> None:
    _replace_columns_via_values(overload, {
        "DX": overload["R"],
        "DY": overload["G"],
        "DZ": overload["B"]
    })
    dir_vec = Vector((overload["DX"], overload["DY"], overload["DZ"]))
    overload["WIDTH"] = 1 - dir_vec.magnitude
    dvn = dir_vec.normalized()
    _replace_columns_via_values(overload, {
        "DX": dvn[0],
        "DY": dvn[1],
        "DZ": dvn[2]
    })
    _replace_columns_via_values(overload, {"R": 1, "G": 1, "B": 1})
Example #32
0
    def execute(self, context):
        mesh = bmesh.new()
        aux_mesh = bpy.context.object.to_mesh(bpy.context.depsgraph,
                                              apply_modifiers=True,
                                              calc_undeformed=False)
        mesh.from_mesh(aux_mesh)
        mesh.transform(bpy.context.object.matrix_world)
        bpy.data.meshes.remove(aux_mesh)

        internal.addCurveObject(
            'Toolpath').location = bpy.context.scene.cursor_location
        pitch_axis = Vector(self.pitch_axis)
        axis = pitch_axis.normalized()
        for i in range(0, self.slice_count):
            aux_mesh = mesh.copy()
            cut_geometry = bmesh.ops.bisect_plane(
                aux_mesh,
                geom=aux_mesh.edges[:] + aux_mesh.faces[:],
                dist=0,
                plane_co=pitch_axis * i + axis * self.offset,
                plane_no=axis,
                clear_outer=False,
                clear_inner=False)['geom_cut']
            edge_pool = set(
                [e for e in cut_geometry if isinstance(e, bmesh.types.BMEdge)])
            while len(edge_pool) > 0:
                current_edge = edge_pool.pop()
                first_vertex = current_vertex = current_edge.verts[0]
                vertices = [current_vertex.co]
                follow_edge_loop = len(edge_pool) > 0
                while follow_edge_loop:
                    current_vertex = current_edge.other_vert(current_vertex)
                    vertices.append(current_vertex.co)
                    if current_vertex == first_vertex:
                        break
                    follow_edge_loop = False
                    for edge in current_vertex.link_edges:
                        if edge in edge_pool:
                            current_edge = edge
                            edge_pool.remove(current_edge)
                            follow_edge_loop = True
                            break
                current_vertex = current_edge.other_vert(current_vertex)
                vertices.append(current_vertex.co)
                internal.addPolygonSpline(bpy.context.object, False, vertices)
            aux_mesh.free()

        return {'FINISHED'}
Example #33
0
    def to_line(self, amplitude, coefficient, vertex, centers, direction):
        center = Vector(centers[0])
        direction = Vector(direction)
        dirlength = direction.length
        if dirlength <= 0:
            raise ValueError("Direction vector must have nonzero length!")
        vertex = Vector(vertex)

        to_center = center - vertex
        # cosine of angle between to_center and direction
        cos_phi = to_center.dot(direction) / (to_center.length * dirlength)
        # projection of to_center on direction
        to_center_projection = to_center.length * cos_phi * direction.normalized()
        # projection of vertex on direction
        projection = center - to_center_projection
        vector = projection - vertex
        return self.falloff(amplitude, coefficient, vector.length), vector.normalized()
 def add_torus(self, majSeg, minSeg, majRad, minRad):
     lv = []
     circ = math.pi * 2
     majCirc = circ / majSeg
     minCirc = circ / minSeg
     index = 0
     rings = []
     for maj in range(majSeg):
         majTheta = majCirc * maj
         dx = math.cos(majTheta) * majRad
         dy = math.sin(majTheta) * majRad
         n = Vector((dx, dy, 0))
         minorRing = []
         for min in range(minSeg):
             minTheta = minCirc * min
             dn = math.cos(minTheta) * minRad
             dz = math.sin(minTheta) * minRad
             co = n + n.normalized() * dn + Vector((0, 0, dz))
             co = co.to_tuple()
             lv.append(self.new_vertex((Vector((co)))))
             minorRing.append(index)
             index += 1
         rings.append(minorRing)
     for ri in range(len(rings) - 1):
         ring = rings[ri]
         nextRing = rings[ri + 1]
         for i in range(len(ring) - 1):
             self.new_face([
                 lv[ring[i]], lv[nextRing[i]], lv[nextRing[i + 1]],
                 lv[ring[i + 1]]
             ])
         self.new_face([
             lv[ring[0]], lv[ring[len(ring) - 1]],
             lv[nextRing[len(nextRing) - 1]], lv[nextRing[0]]
         ])
     ring = rings[len(rings) - 1]
     nextRing = rings[0]
     for i in range(len(ring) - 1):
         self.new_face([
             lv[ring[i]], lv[nextRing[i]], lv[nextRing[i + 1]],
             lv[ring[i + 1]]
         ])
     self.new_face([
         lv[ring[0]], lv[ring[len(ring) - 1]],
         lv[nextRing[len(nextRing) - 1]], lv[nextRing[0]]
     ])
def torus(majSeg, minSeg, majRad, minRad):
    lp = []
    lf = []

    circ = math.pi * 2
    majCirc = circ / majSeg
    minCirc = circ / minSeg

    index = 0

    rings = []

    for maj in range(majSeg):
        majTheta = majCirc * maj
        dx = math.cos(majTheta) * majRad
        dy = math.sin(majTheta) * majRad
        n = Vector((dx, dy, 0))

        minorRing = []
        for min in range(minSeg):
            minTheta = minCirc * min
            dn = math.cos(minTheta) * minRad
            dz = math.sin(minTheta) * minRad

            co = n + n.normalized() * dn + Vector((0, 0, dz))
            co = co.to_tuple()
            lp.append(co)
            minorRing.append(index)
            index += 1
        rings.append(minorRing)

    for ri in range(len(rings) - 1):
        ring = rings[ri]
        nextRing = rings[ri + 1]
        for i in range(len(ring) - 1):
            lf.append((ring[i], nextRing[i], nextRing[i + 1], ring[i + 1]))
        lf.append((ring[0], ring[len(ring) - 1], nextRing[len(nextRing) - 1],
                   nextRing[0]))
    ring = rings[len(rings) - 1]
    nextRing = rings[0]
    for i in range(len(ring) - 1):
        lf.append((ring[i], nextRing[i], nextRing[i + 1], ring[i + 1]))
    lf.append((ring[0], ring[len(ring) - 1], nextRing[len(nextRing) - 1],
               nextRing[0]))

    return lp, lf
def torus(majSeg, minSeg, majRad, minRad):
    lp = []
    lf = []
    
    circ = math.pi*2
    majCirc = circ/majSeg
    minCirc = circ/minSeg
    
    index = 0
    
    rings = []
    
    for maj in range(majSeg):
        majTheta = majCirc*maj
        dx = math.cos(majTheta) * majRad
        dy = math.sin(majTheta) * majRad
        n = Vector((dx, dy, 0))
        
        minorRing = []
        for min in range(minSeg):
            minTheta = minCirc*min
            dn = math.cos(minTheta) * minRad
            dz = math.sin(minTheta) * minRad
            
            co = n + n.normalized() * dn + Vector((0, 0, dz))
            co = co.to_tuple()
            lp.append(co)
            minorRing.append(index)
            index += 1
        rings.append(minorRing)
    
    for ri in range(len(rings)-1):
        ring = rings[ri]
        nextRing = rings[ri+1]
        for i in range(len(ring)-1):
            lf.append((ring[i], nextRing[i], nextRing[i+1], ring[i+1]))
        lf.append((ring[0], ring[len(ring)-1], nextRing[len(nextRing)-1], nextRing[0]))
    ring = rings[len(rings)-1]
    nextRing = rings[0]
    for i in range(len(ring)-1):
        lf.append((ring[i], nextRing[i], nextRing[i+1], ring[i+1]))
    lf.append((ring[0], ring[len(ring)-1], nextRing[len(nextRing)-1], nextRing[0]))
    
    return lp, lf   
Example #37
0
def bevel(ob, follow, beveltype):
    me = ob.data

    # dict
    vvdict = vert_vert_dict(me, sel=0)
    vedict = vert_edge_dict(me, sel=0)
    vfdict = vert_face_dict(me, sel=0)
    efdict = edge_face_dict(me, sel=0)
    kedict = key_edge_dict_old(me, sel=0)

    bevelverts = []
    bevelvertindex = len(me.vertices)
    bevelfaces = bfaces = []
    bevelfaces_material = bfmats = []
    # ekparallel: 既存の辺からbevelされた辺を参照。面を張る為にkeyをsortedしない
    ekparallel = [[] for e in me.edges]
    vvparallel = [set() for v in me.vertices]

    #共通の頂点を探したりする
    '''vevparallel = {v.index:{kedict[key]:None for key in vedict[v.index]} \
                   for v in me.vertices}
    '''
    vevparallel = {}
    for v in me.vertices:
        if not v.hide:
            evdict = {}
            for key in vedict[v.index]:
                evdict[kedict[key]] = None
            vevparallel[v.index] = evdict
    # bevelで削除される予定頂点から生成される辺を参照
    vkparallel = {v.index:[] for v in me.vertices}

    vertflags = [0 for v in me.vertices]
    #edgeflags = [e.index for e in me.edges]
    faceflags = [0 for f in me.faces]

    # flag作り
    for i in range(len(me.vertices)):
        # hiddenも処理
        if me.vertices[i].hide:
            continue
        tmp = [0, 0]
        for key in vedict[i]:
            if len(efdict[key]) == 0:
                tmp[0] += 1
            else:
                tmp[1] += 1
        if sum(tmp) == 0:
            vertflags[i] |= VERT
        elif tmp[0] >= 1 and tmp[1] == 0:
            vertflags[i] |= EDGE
        elif tmp[0] == 0 and tmp[1] >= 1:
            vertflags[i] |= FACE
        else:
            vertflags[i] |= MIX
    # flag作り2
    for e in me.edges:
        if e.key in efdict:
            if len(efdict[e.key]) > 2:
                vertflags[e.key[0]] |= MIX
                vertflags[e.key[1]] |= MIX

    # Face
    for face in me.faces:
        if face.hide:
            continue

        findex = face.index
        material = face.material_index

        vcor = {i:[] for i in face.vertices} # 新旧対応 correspond
        vflags = {i:0 for i in face.vertices}

        edge_keys = face.edge_keys

        # 頂点ループ?
        fverts = list(face.vertices)
        for vindex in fverts:
            vert = me.vertices[vindex]

            if not vert.select:
                continue
            if vertflags[vindex] & MIX:
                continue

            # 順番を考慮
            #connected_edges = [me.edges[kedict[key]] for key in edge_keys
            #                   if key in vedict[vindex]]
            connected_edges = [key for key in edge_keys if vindex in key]
            if connected_edges == [edge_keys[0], edge_keys[-1]]:
                connected_edges.reverse()
            #if edge_keys.index(connected_edges[0]) == 0 and \
            #   edge_keys.index(connected_edges[1]) == len(edge_keys) - 1:
            #    connected_edges.reverse()
            e1, e2 = [me.edges[kedict[key]] for key in connected_edges]

            key1 = e1.key
            key2 = e2.key
            v1i = the_other(key1, vindex)
            v2i = the_other(key2, vindex)
            va0 = vert.co
            va1 = me.vertices[v1i].co # edge1
            va2 = me.vertices[v2i].co # edge2
            vac = face.center
            vr01 = va1 - va0
            vr02 = va2 - va0
            vr0c = vac - va0

            if beveltype == 'vert':
                vflags[vindex] = VERT
            elif e1.select and e2.select:
                tmp = [len(efdict[e1.key]), len(efdict[e2.key])]
                if tmp[0] == 1 and tmp[1] == 1:
                    vflags[vindex] = VERT
                elif tmp[0] == 2 and tmp[1] == 1:
                    ea, eb, vra, vrb = e2, e1, vr02, vr01
                    vflags[vindex] = EDGE
                elif tmp[0] == 1 and tmp[1] == 2:
                    ea, eb, vra, vrb = e1, e2, vr01, vr02
                    vflags[vindex] = EDGE
                else:
                    vflags[vindex] = FACE
            elif not e1.select and not e2.select:
                vflags[vindex] = VERT
            else:
                eb = e1 if e1.select else e2
                if len(efdict[eb.key]) == 1:
                    vflags[vindex] = VERT
                else:
                    vflags[vindex] = EDGE
                    if e1.select:
                        ea, eb, vra, vrb = e2, e1, vr02, vr01
                    else:
                        ea, eb, vra, vrb = e1, e2, vr01, vr02

            if vflags[vindex] == FACE:
                # 両方のエッジが選択
                # エッジの角度が180度以上になる場合は予期しない結果になる
                vr010c_cross = vr01.cross(vr0c).normalized()
                angle = vr01.angle(vr02)
                q = axis_angle_to_quat(vr010c_cross, angle / 2)
                v = q * vr01 
                v.normalize()
                if angle > SMALL_NUMBER:
                    s = math.sin(angle / 2)
                    v *= 1.0 / s
                else:
                    v = Vector((0, 0, 0))
                #co = va0 + v # absolute coordinate
                co = va0.copy()

                bevelvert = BVert(v, co, bevelvertindex,
                                  vindex, e1.index, findex)# e1, e2どちらを優先しても可
                bevelvert.ebi = e2.index
                bevelvert.f = FACE
                bevelverts.append(bevelvert)
                vcor[vindex].append(bevelvert.vi) # == bevelvertindex
                #vflags[vindex] = FACE
                bevelvertindex += 1
            elif vflags[vindex] == VERT:
                # 両方のエッジが非選択
                # 頂点をエッジに沿って分割
                for ea, eb, v in [(e1, e2, vr01), (e2, e1, vr02)]:
                    vei = vevparallel[vindex][ea.index]
                    if not vei:
                        v = v.normalized()
                        #co = va0 + v
                        co = va0.copy()
                        bevelvert = BVert(v, co, bevelvertindex,
                                          vindex, ea.index, findex)
                        bevelvert.ebi = eb.index # bevelされた辺
                        bevelvert.f = VERT
                        bevelverts.append(bevelvert)
                        vevparallel[vindex][ea.index] = bevelvert.vi
                        bevelvertindex += 1
                    else:
                        bevelvert = bevelverts[vei - len(me.vertices)]
                        bevelvert.eb2i = eb.index
                        bevelvert.f2i = findex
                    vcor[vindex].append(bevelvert.vi)
                #vflags[vindex] = VERT
            else:
                # 片側のエッジが選択
                # 非選択エッジのみに頂点追加
                '''
                if e1.select:
                    ea, eb, vra, vrb = e2, e1, vr02, vr01
                else:
                    ea, eb, vra, vrb = e1, e2, vr01, vr02
                '''
                vra = vra.normalized()
                vrb = vrb.normalized()
                angle = vra.angle(vrb)
                if angle > SMALL_NUMBER:
                    v = vra / math.sin(angle)
                    #co = va0 + v
                else:
                    v = Vector([0, 0, 0])
                co = va0.copy()

                vei = vevparallel[vindex][ea.index]
                if not vei:
                    bevelvert = BVert(v, co, bevelvertindex,
                                      vindex, ea.index, findex)
                    bevelvert.ebi = eb.index # bevelされた辺
                    bevelvert.f = EDGE
                    bevelverts.append(bevelvert)
                    vevparallel[vindex][ea.index] = bevelvert.vi
                    bevelvertindex += 1
                else:
                    bevelvert = bevelverts[vei - len(me.vertices)]
                    bevelvert.vec = (v +  bevelvert.vec) / 2 # 平均化
                    #bevelvert.co = va0 + bevelvert.vec
                    bevelvert.eb2i = eb.index
                    bevelvert.f2i = findex
                vcor[vindex].append(bevelvert.vi)
                #vflags[vindex] = EDGE

        # vvparallel
        for k, verts in vcor.items():
            for v in verts:
                vvparallel[k].add(v)

        if sum(vflags.values()) == 0: # 選択頂点無し
            continue

        # 面作成、辺・頂点削除指定
        # 元頂点のflag vflags
        vfl = list(vflags.values())
        vf = (vfl.count(VERT), vfl.count(EDGE), vfl.count(FACE))

        if len(face.vertices) == 4:
            if vf[0] == 1:
                v0 = [k for k, v in vflags.items() if v == VERT][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 3] # next
                v2 = fverts[v0_i - 2] # diagonal
                v3 = fverts[v0_i - 1] # prev
                if vf == (1, 0, 0):
                    # *** CAUTION *** #
                    #bfaces.append([vcor[v0][0], vcor[v0][1]], v1, v3)
                    #上記の順だと上手く張れない面が出る
                    bfaces.append([v1, v3, vcor[v0][0], vcor[v0][1]])
                    bfaces.append([v1, v2, v3])
                    # material
                    bfmats.extend([material, material])
                    # delete
                    vertflags[v0] |= DELETE
                elif vf == (1, 2, 0):
                    if vflags[v1] == EDGE:
                        bfaces.append([vcor[v0][0], vcor[v0][1],
                                       vcor[v1][0], v3])
                        bfaces.append([vcor[v1][0], vcor[v2][0], v3])
                        # material
                        bfmats.extend([material, material])
                        # ekparallel
                        key = [vcor[v1][0], vcor[v2][0]]
                        dkey = tuple(sorted([v1, v2]))
                        ekparallel[kedict[dkey]].append(key)
                        # delete
                        vertflags[v1] |= DELETE
                        vertflags[v2] |= DELETE
                    else:
                        bfaces.append([vcor[v0][0], vcor[v0][1],
                                       v1, vcor[v3][0]])
                        bfaces.append([v1, vcor[v2][0], vcor[v3][0]])
                        # material
                        bfmats.extend([material, material])
                        # ekparallel
                        key = [vcor[v2][0], vcor[v3][0]]
                        dkey = tuple(sorted([v2, v3]))
                        ekparallel[kedict[dkey]].append(key)
                        # delete
                        vertflags[v2] |= DELETE
                        vertflags[v3] |= DELETE
                else:
                    # vf == (1,2,1)
                    bfaces.append([vcor[v0][0], vcor[v0][1],
                                   vcor[v1][0], vcor[v3][0]])
                    bfaces.append([vcor[v1][0], vcor[v2][0], vcor[v3][0]])
                    # material
                    bfmats.extend([material, material])
                    # ekparallel
                    for i, j in [[v1, v2], [v2, v3]]:
                        key = [vcor[i][0], vcor[j][0]]
                        dkey = tuple(sorted([i, j]))
                        ekparallel[kedict[dkey]].append(key)
                    # delete
                    for i in [v1, v2, v3]:
                        vertflags[i] |= DELETE
                # vkparallel
                vkparallel[v0].append([vcor[v0][1], vcor[v0][0]])
                # delete
                vertflags[v0] |= DELETE

            elif vf[0] == 2:
                v0 = [k for k, v in vflags.items() if v == VERT][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 3]
                v2 = fverts[v0_i - 2]
                v3 = fverts[v0_i - 1]
                if EDGE not in vfl:
                    # vf == (2, 0, 0)
                    if vflags[v1] == VERT:
                        bfaces.append([vcor[v0][0], vcor[v0][1],
                                       vcor[v1][0], vcor[v1][1]])
                        bfaces.append([vcor[v0][0], vcor[v1][1], v2, v3])
                        # material
                        bfmats.extend([material, material])
                        # vkparallel
                        vkparallel[v1].append([vcor[v1][1], vcor[v1][0]])
                        # delete
                        vertflags[v1] |= DELETE
                    elif vflags[v3] == VERT:
                        bfaces.append([vcor[v3][0], vcor[v3][1],
                                       vcor[v0][0], vcor[v0][1]])
                        bfaces.append([vcor[v3][0], vcor[v0][1], v1, v2])
                        bfmats.extend([material, material])
                        # vkparallel
                        vkparallel[v3].append([vcor[v3][1], vcor[v3][0]])
                        # delete
                        vertflags[v3] |= DELETE
                    elif vflags[v2] == VERT: # diagonal
                        bfaces.append([vcor[v0][0], vcor[v0][1], v1, v3])
                        bfaces.append([vcor[v2][0], vcor[v2][1], v3, v1])
                        # material
                        bfmats.extend([material, material])
                        # vkparallel
                        vkparallel[v2].append([vcor[v2][1], vcor[v2][0]])
                        # delete
                        vertflags[v2] |= DELETE
                    # delete
                    vertflags[v0] |= DELETE
                else:
                    # vf == (2, 2, 0)
                    if vflags[v1] == VERT:
                        bfaces.append([vcor[v0][0], vcor[v0][1],
                                       vcor[v1][0], vcor[v1][1]])
                        bfaces.append([vcor[v0][1], vcor[v1][0],
                                       vcor[v2][0], vcor[v3][0]])
                        # material
                        bfmats.extend([material, material])
                        # vkparallel
                        vkparallel[v1].append([vcor[v1][1], vcor[v1][0]])
                        # ekparallel
                        key = [vcor[v2][0], vcor[v3][0]]
                        dkey = tuple(sorted([v2, v3]))
                        ekparallel[kedict[dkey]].append(key)
                    if vflags[v3] == VERT:
                        bfaces.append([vcor[v3][0], vcor[v3][1],
                                       vcor[v0][0], vcor[v0][1]])
                        bfaces.append([vcor[v3][0], vcor[v0][1],
                                       vcor[v1][0], vcor[v2][0]])
                        # material
                        bfmats.extend([material, material])
                        # vkparallel
                        vkparallel[v3].append([vcor[v3][1], vcor[v3][0]])
                        # ekparallel
                        key = [vcor[v1][0], vcor[v2][0]]
                        dkey = tuple(sorted([v1, v2]))
                        ekparallel[kedict[dkey]].append(key)
                    # delete
                    for i in fverts:
                        vertflags[i] |= DELETE
                # vkparallel
                vkparallel[v0].append([vcor[v0][1], vcor[v0][0]])

            elif vf == (3, 0, 0):
                v0 = [k for k, v in vflags.items() if v == 0][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 3]
                v2 = fverts[v0_i - 2]
                v3 = fverts[v0_i - 1]
                bfaces.append([v0, vcor[v1][0], vcor[v3][1]])
                bfaces.append([vcor[v1][0], vcor[v1][1],
                               vcor[v3][0], vcor[v3][1]])
                bfaces.append([vcor[v1][1], vcor[v2][0],
                               vcor[v2][1], vcor[v3][0]])
                # material
                bfmats.extend([material, material, material])
                # vkparallel
                for i in [v1, v2, v3]:
                    vkparallel[i].append([vcor[i][1], vcor[i][0]])
                # delete
                for i in [v1, v2, v3]:
                    vertflags[i] |= DELETE

            elif vf == (4, 0, 0):
                v0 = [k for k, v in vflags.items() if v == VERT][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 3]
                v2 = fverts[v0_i - 2]
                v3 = fverts[v0_i - 1]
                '''
                bfaces.append([vcor[v0][0], vcor[v0][1],
                               vcor[v1][0], vcor[v3][1]])
                bfaces.append([vcor[v1][0], vcor[v1][1],
                               vcor[v3][0], vcor[v3][1]])
                bfaces.append([vcor[v1][1], vcor[v2][0],
                               vcor[v2][1], vcor[v3][0]])
                '''
                bfaces.append([vcor[v0][0], vcor[v0][1],
                               vcor[v1][0], vcor[v1][1]])
                bfaces.append([vcor[v1][1], vcor[v2][0],
                               vcor[v3][1], vcor[v0][0]])
                bfaces.append([vcor[v2][0], vcor[v2][1],
                               vcor[v3][0], vcor[v3][1]])
                # material
                bfmats.extend([material, material, material])
                # vkparallel
                for i in [v0, v1, v2, v3]:
                    vkparallel[i].append([vcor[i][1], vcor[i][0]])
                # delete
                for i in fverts:
                    vertflags[i] |= DELETE

            elif vf == (0, 2, 0):
                v0 = [k for k, v in vflags.items() if v == EDGE][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 3]
                v2 = fverts[v0_i - 2]
                v3 = fverts[v0_i - 1]
                if vflags[v1] != EDGE:
                    v0 = fverts[fverts.index(v0) - 1]
                    v1 = fverts[fverts.index(v1) - 1]
                    v2 = fverts[fverts.index(v2) - 1]
                    v3 = fverts[fverts.index(v3) - 1]
                #bfaces.append([vcor[v0][0], vcor[v1][0], v2, v3])
                bfaces.append([v2, v3, vcor[v0][0], vcor[v1][0]])
                # material
                bfmats.extend([material])
                # ekparallel
                key = [vcor[v0][0], vcor[v1][0]]
                dkey = tuple(sorted([v0, v1]))
                ekparallel[kedict[dkey]].append(key)
                # delete
                vertflags[v0] |= DELETE
                vertflags[v1] |= DELETE

            elif vf == (0, 4, 0):
                bfaces.append([vcor[i][0] for i in fverts])
                # material
                bfmats.extend([material])
                # ekparallel
                keys = [(fverts[i - 1], fverts[i]) for i in range(4)]
                selkeys = [key for key in face.edge_keys
                           if me.edges[kedict[key]].select]
                keys = [key for key in keys if tuple(sorted(key)) in selkeys]
                for k in keys:
                    v0, v1 = k
                    key = [vcor[v0][0], vcor[v1][0]]
                    dkey = tuple(sorted([v0, v1]))
                    ekparallel[kedict[dkey]].append(key)
                # delete
                for i in fverts:
                    vertflags[i] |= DELETE

            elif vf == (0, 2, 1):
                v0 = [k for k, v in vflags.items() if v == FACE][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 3]
                v2 = fverts[v0_i - 2]
                v3 = fverts[v0_i - 1]
                bfaces.append([vcor[v0][0], vcor[v1][0], v2, vcor[v3][0]])
                # material
                bfmats.extend([material])
                # ekparallel
                for i, j in [[v0, v1], [v3, v0]]:
                    key = [vcor[i][0], vcor[j][0]]
                    dkey = tuple(sorted([i, j]))
                    ekparallel[kedict[dkey]].append(key)
                # delete
                for i in [v0, v1, v3]:
                    vertflags[i] |= DELETE

            elif vf == (0, 2, 2):
                v0 = [k for k, v in vflags.items() if v == EDGE][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 3]
                v2 = fverts[v0_i - 2]
                v3 = fverts[v0_i - 1]
                if vflags[v1] != FACE:
                    v0 = fverts[fverts.index(v0) - 3]
                    v1 = fverts[fverts.index(v1) - 3]
                    v2 = fverts[fverts.index(v2) - 3]
                    v3 = fverts[fverts.index(v3) - 3]
                bfaces.append([vcor[i][0] for i in fverts])
                # material
                bfmats.extend([material])
                # ekparallel
                for i, j in [[v0, v1], [v1, v2], [v2, v3]]:
                    key = [vcor[i][0], vcor[j][0]]
                    dkey = tuple(sorted([i, j]))
                    ekparallel[kedict[dkey]].append(key)
                # delete
                for i in fverts:
                    vertflags[i] |= DELETE

            elif vf == (0, 0, 4):
                v0, v1, v2, v3 = fverts
                bfaces.append([vcor[v0][0], vcor[v1][0],
                               vcor[v2][0], vcor[v3][0]])
                # material
                bfmats.extend([material])
                # ekparallel
                for i, j in [[v0, v1], [v1, v2], [v2, v3], [v3, v0]]:
                    key = [vcor[i][0], vcor[j][0]]
                    dkey = tuple(sorted([i, j]))
                    ekparallel[kedict[dkey]].append(key)
                # delete
                for i in fverts:
                    vertflags[i] |= DELETE
            else:
                continue

        else: # Triangle
            if vf == (1, 0, 0):
                v0 = [k for k, v in vflags.items() if v == VERT][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 2]
                v2 = fverts[v0_i - 1]
                #bfaces.append([vcor[v0][0], vcor[v0][1], v1, v2])
                bfaces.append([v1, v2, vcor[v0][0], vcor[v0][1]])
                # material
                bfmats.extend([material])
                # vkparallel
                vkparallel[v0].append([vcor[v0][1], vcor[v0][0]])
                # delete
                vertflags[v0] |= DELETE
            elif vf == (1, 2, 0):
                v0 = [k for k, v in vflags.items() if v == VERT][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 2]
                v2 = fverts[v0_i - 1]
                bfaces.append([vcor[v0][0], vcor[v0][1],
                               vcor[v1][0], vcor[v2][0]])
                # material
                bfmats.extend([material])
                # vkparallel
                vkparallel[v0].append([vcor[v0][1], vcor[v0][0]])
                # ekparallel
                key = [vcor[v1][0], vcor[v2][0]]
                dkey = tuple(sorted([v1, v2]))
                ekparallel[kedict[dkey]].append(key)
                # delete
                vertflags[v0] |= DELETE
            elif vf == (2, 0, 0):
                v0 = [k for k, v in vflags.items() if v == 0][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 2]
                v2 = fverts[v0_i - 1]
                bfaces.append([v0, vcor[v1][0], vcor[v2][1]])
                bfaces.append([vcor[v1][0], vcor[v1][1],
                               vcor[v2][0], vcor[v2][1]])
                # material
                bfmats.extend([material, material])
                # vkparallel
                for i in [v1, v2]:
                    vkparallel[i].append([vcor[i][1], vcor[i][0]])
                # delete
                vertflags[v1] |= DELETE
                vertflags[v2] |= DELETE
            elif vf == (3, 0, 0):
                v0 = [k for k, v in vflags.items() if v == VERT][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 2]
                v2 = fverts[v0_i - 1]
                bfaces.append([vcor[v0][0], vcor[v0][1],
                               vcor[v1][0], vcor[v2][1]])
                bfaces.append([vcor[v1][0], vcor[v1][1],
                               vcor[v2][0], vcor[v2][1]])
                # material
                bfmats.extend([material, material])
                # vkparallel
                for i in [v0, v1, v2]:
                    vkparallel[i].append([vcor[i][1], vcor[i][0]])
                # delete
                for i in fverts:
                    vertflags[i] |= DELETE
            elif vf == (0, 2, 0):
                v0 = [k for k, v in vflags.items() if v == 0][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 2]
                v2 = fverts[v0_i - 1]
                bfaces.append([v0, vcor[v1][0], vcor[v2][0]])
                # material
                bfmats.extend([material])
                # ekparallel
                key = [vcor[v1][0], vcor[v2][0]]
                dkey = tuple(sorted([v1, v2]))
                ekparallel[kedict[dkey]].append(key)
                # delete
                vertflags[v1] |= DELETE
                vertflags[v2] |= DELETE
            elif vf == (0, 2, 1):
                v0 = [k for k, v in vflags.items() if v == FACE][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 2]
                v2 = fverts[v0_i - 1]
                bfaces.append([vcor[v0][0], vcor[v1][0], vcor[v2][0]])
                # material
                bfmats.extend([material])
                # ekparallel
                for i, j in [[v0, v1], [v2, v0]]:
                    key = [vcor[i][0], vcor[j][0]]
                    dkey = tuple(sorted([i, j]))
                    ekparallel[kedict[dkey]].append(key)
                # delete
                for i in fverts:
                    vertflags[i] |= DELETE
            elif vf == (0, 0, 3):
                v0 = [k for k, v in vflags.items() if v == FACE][0]
                v0_i = fverts.index(v0)
                v1 = fverts[v0_i - 2]
                v2 = fverts[v0_i - 1]
                bfaces.append([vcor[v0][0], vcor[v1][0], vcor[v2][0]])
                # material
                bfmats.extend([material])
                # ekparallel
                for i, j in [[v0, v1], [v1, v2], [v2, v0]]:
                    key = [vcor[i][0], vcor[j][0]]
                    dkey = tuple(sorted([i, j]))
                    ekparallel[kedict[dkey]].append(key)
                # delete
                for i in fverts:
                    vertflags[i] |= DELETE
            else:
                continue

        # delete
        faceflags[findex] |= DELETE

    # active material
    if ob.active_material in list(me.materials):
        actmat = list(me.materials).index(ob.active_material)
    else:
        actmat = None

    # bevel・消去された辺に面を張る
    for eindex, edges in enumerate(ekparallel):
        #if edges:
        if len(edges) == 2: # 判定不要?
            v0, v1 = edges[0] # 新規頂点
            v2, v3 = edges[1]
            #bfaces.append([v3, v2, v1, v0]) # 法線を合わせる為に逆転
            bfaces.append([v1, v0, v3, v2]) # 法線を合わせる為に逆転
            # material
            key = me.edges[eindex].key
            fmats = [me.faces[i].material_index for i in efdict[key]]
            samemat = True
            fmat = fmats[0]
            for i in fmats:
                if i != fmat:
                    samemat = False
            if samemat:
                bfmats.extend([fmat])
            else:
                bfmats.extend([actmat])

            # add new keys to vkparallel
            key1 = (v1, v2)
            key2 = (v3, v0)
            for v in me.edges[eindex].key:
                vv_verts = vvparallel[v]
                if key1[0] in vv_verts or key1[1] in vv_verts:
                    vkparallel[v].append(key1)
                else:
                    vkparallel[v].append(key2)

    # bevel・消去された頂点(flag:VERT)に面を張る
    # vkparallelのkeyは、面を張るために逆転済み
    for vi, keys in vkparallel.items():
        if len(keys) < 2:
            continue

        verts = keypath(keys)
        if not verts:
            continue

        if len(verts) <= 4:
            bfaces.append(verts)
            # material
            #bfmats.extend([actmat])
        else:
            faces = fill(verts)
            bfaces.extend(faces)
            # material
            #bfmats.extend([actmat for i in range(len(faces))])

        # material
        fmats = [me.faces[i].material_index for i in vfdict[vi]]
        samemat = True
        fmat = fmats[0]
        for i in fmats:
            if i != fmat:
                samemat = False
        if len(verts) <= 4:
            fnum = 1
        else:
            fnum = len(faces)
        if samemat:
            bfmats.extend([fmat for i in range(fnum)])
        else:
            bfmats.extend([actmat for i in range(fnum)])

    # edge
    beveledges = bedges = []
    '''vevparallel = {v.index:{kedict[key]:None for key in vedict[v.index]}
                   for v in me.vertices if len(vedict[v.index]) == 2}
    '''
    vevparallel = {}
    for v in me.vertices:
        if v.hide:
            continue
        if v.index not in vedict:
            continue
        if len(vedict[v.index]) == 2:
            evdict = {}
            for key in vedict[v.index]:
                evdict[kedict[key]] = None
            vevparallel[v.index] = evdict

    for vertex in me.vertices:
        vindex = vertex.index
        if not vertex.select or vertex.hide:
            continue
        if not vertflags[vindex] & EDGE:
            continue

        keys = vedict[vindex]
        if len(keys) != 2:
            continue

        e1 = me.edges[kedict[keys[0]]]
        e2 = me.edges[kedict[keys[1]]]
        if e1.hide or e2.hide:
            continue

        everts = []
        va0 = me.vertices[vindex].co
        for edge in [e1, e2]:
            va1 = me.vertices[the_other(edge.key, vindex)].co
            vr01 = va1 - va0
            vr01.normalize()
            v = vr01
            co = va0.copy()
            bevelvert = BVert(v, co, bevelvertindex,
                              vindex, edge.index, None)
            bevelvert.f = VERT
            bevelverts.append(bevelvert)
            vevparallel[vindex][edge.index] = bevelvert.vi
            everts.append(bevelvert.vi)
            bevelvertindex += 1
        bedges.append(sorted(everts)) # sortedの必要無し?
        # delete
        vertflags[vindex] |= DELETE

    for edge in me.edges:
        conti = 0
        for i in edge.key:
            v = me.vertices[i]
            #if not v.select or v.hide or not vertflags[vindex] & EDGE:
            if (not v.select) or v.hide or (not vertflags[i] & EDGE):
                conti =+ 1
        if conti == 2:
            continue

        v1, v2 = edge.key
        vb1 = vevparallel[v1][edge.index] if v1 in vevparallel else v1
        vb2 = vevparallel[v2][edge.index] if v2 in vevparallel else v2
        if vb1 and vb2:
            bedges.append(sorted([vb1, vb2]))

    # delverts
    delverts = [i for i, v in enumerate(vertflags) if v & DELETE]

    # delfaces
    #delfaces = [f for f in faceflags if f & DELETE]

    #return bevelverts, beveledges, bevelfaces, delverts, delfaces
    return bevelverts, beveledges, bevelfaces, delverts, bfmats
Example #38
0
	def execute(self, context):
		active_obj = context.scene.objects.active
		if active_obj is None or active_obj.data is None:
			self.report({'ERROR'}, "No active object")
			return {'CANCELLED'}
		active_mesh = active_obj.data
		select_and_change_mode(active_obj, 'EDIT')
		bm = bmesh.from_edit_mesh(active_mesh)
		selvertsIdx = get_bmhistory_vertsIdx(bm)
		if len(selvertsIdx) < 2:
			self.report({'ERROR'}, "Verts History error: Pick source, then target.")
			return {'CANCELLED'}
		verts_snap_map = {}
		verts_snap_nrm_map = {}
		if (active_mesh.uv_textures.get(kWPLPinmapUV) is not None and WPL_G.pinobj == active_obj.name):
			print("Found pinned state, using for reference")
			verts_se_map = {}
			(verts_snap_map,verts_snap_nrm_map,verts_se_map,_,_) = getBmPinmap(active_obj, bm, None)
		else:
			for vert in bm.verts:
				verts_snap_map[vert.index] = vert.co
				verts_snap_nrm_map[vert.index] = vert.normal
		transfScale = Vector(self.opt_scale)
		refp_origin_v = bm.verts[selvertsIdx[1]]
		refp_target_v = bm.verts[selvertsIdx[0]]
		refp_origin = refp_origin_v.co
		refp_target = refp_target_v.co
		transferred = []
		transferMap = [(refp_origin_v,refp_target_v,Vector((0,0,0)))]
		transferStep = 0
		errs1 = 0
		errs2 = 0
		while len(transferMap)>0:
			#print("transferMap", transferMap, "transferStep", transferStep)
			transferMapNext = []
			for tpr in transferMap:
				vSrc = tpr[0]
				vTrg = tpr[1]
				vSrcOffs = tpr[2]
				vSrc_bCo = verts_snap_map[vSrc.index]
				vTrg_bCo = verts_snap_map[vTrg.index]
				# transferring position
				infl = 1.0
				if self.opt_falloff > 0.0:
					infl = 1.0-float(transferStep+1)/float(self.opt_cloneLoops)
					infl = pow(infl,self.opt_falloff)
				vSrcOffsScaled = Vector((vSrcOffs[0]*transfScale[0],vSrcOffs[1]*transfScale[1],vSrcOffs[2]*transfScale[2]))
				vTrg.co = vTrg.co.lerp(refp_target+vSrcOffsScaled, infl)
				transferred.append(vSrc.index)
				transferred.append(vTrg.index)
				if transferStep < self.opt_cloneLoops:
					# moving to next
					srcNxt = []
					for eSrc in vSrc.link_edges:
						vSrc2 = eSrc.other_vert(vSrc)
						if vSrc2.index in transferred or vSrc2.hide > 0:
							continue
						vSrc2_bCo = verts_snap_map[vSrc2.index]
						parentDir = (vSrc2_bCo-vSrc_bCo)
						parentDir = parentDir.normalized()
						srcNxt.append((vSrc2, parentDir))
					trgNxt = []
					trgNxtUsed = []
					# Find nearest end point among target endes for each source edge
					for i,vprSrc in enumerate(srcNxt):
						nearestDst = 9999
						nearestVrt = None
						for eTrg in vTrg.link_edges:
							vTrg2 = eTrg.other_vert(vTrg)
							if vTrg2.index in transferred or vTrg2.hide > 0:
								continue
							vTrg2_bCo = verts_snap_map[vTrg2.index]
							parentDir = (vTrg2_bCo-vTrg_bCo)
							parentDir = Vector((parentDir[0]*transfScale[0],parentDir[1]*transfScale[1],parentDir[2]*transfScale[2]))
							parentDir = parentDir.normalized()
							srcELen = (parentDir-vprSrc[1]).length
							if srcELen < nearestDst: # to avoid miscast on 1-unit distance
								if srcELen < 0.99 or len(trgNxt)-len(srcNxt)<2:
									nearestDst = srcELen
									nearestVrt = vTrg2
						# TBD: other matching means
						if (nearestVrt is not None) and (nearestVrt not in trgNxtUsed):
							trgNxtUsed.append(nearestVrt)
							trgNxt.append((nearestVrt, nearestDst))
						else:
							errs1 = errs1+1
					if len(srcNxt) == len(trgNxt) and len(trgNxt)>0:
						#print("srcNxt", srcNxt)
						#print("trgNxt", trgNxt)
						for i,vprSrc in enumerate(srcNxt):
							vprTrg = trgNxt[i]
							vSrcOffs = vprSrc[0].co-refp_origin
							nextstep = (vprSrc[0],vprTrg[0],vSrcOffs)
							transferMapNext.append(nextstep)
					else:
						errs2 = errs2+1
						# easily on mesh bounds -> just skipping
						#self.report({'ERROR'}, "Stopped at topology difference")
						#transferMapNext = []
			transferMap = transferMapNext
			transferStep = transferStep+1
		bm.normal_update()
		bmesh.update_edit_mesh(active_mesh, True)
		self.report({'INFO'}, "Snapped: "+ str(int(len(transferred)/2))+" in "+str(transferStep)+" steps; Skipped:"+str(errs1)+"/"+str(errs2))
		return {'FINISHED'}
    def calc_weighted_normal(bm, vert_index, edge_index):
        """Calculates weighted normal for given combination of vertex and edge index.
        WARNING: There is no safety chec if thoose two belongs together.

        :param bm: bmesh object
        :type bm: bmesh
        :param vert_index: index of the vertex to calculate normal for
        :type vert_index: int
        :param edge_index: index of the edge to use for calculation (vertex has to belong to this edge)
        :returns: Vector
        """
        normal_hash = str(vert_index) + ":" + str(edge_index)

        if normal_hash in WeightNormalsCalculator.cache:
            return WeightNormalsCalculator.cache[normal_hash]

        edge = bm.edges[edge_index]
        vert = bm.verts[vert_index]

        selected_faces = []

        # edge.seam = True
        # edge.select_set(True)

        for f in edge.link_faces:

            if not f.select:

                f.select = True
                selected_faces.append(f)

        # select linked faces of already selected edges
        # until every smooth face around current loop is selected
        more_selected = 1
        while more_selected > 0:

            more_selected = 0
            for edge1 in vert.link_edges:

                if edge1.smooth and edge1.select:

                    for f in edge1.link_faces:

                        if not f.select:

                            f.select = True
                            selected_faces.append(f)

                            more_selected += 1

        # calc areas
        max_area = 0
        areas = {}
        for i, f in enumerate(selected_faces):
            area = f.calc_area()
            areas[i] = area

            if area > max_area:
                max_area = area

        # calc normal
        normal = Vector()
        for i, f in enumerate(selected_faces):
            perc = areas[i] / max_area
            f.normal_update()
            normal += perc * f.normal

            # also unselect all the faces
            f.select = False

        WeightNormalsCalculator.cache[normal_hash] = normal.normalized()

        return normal.normalized()
Example #40
0
    def determine_influence(self, octree, falloff_curve,
                            ignore_backfacing=False, mesh_object=None):
        coordinate_map = octree.coordinate_map
        map_manager = MapManager()
        primary_brush = self.primary_brush
        vertex_filter = VertexFilter()
        vertex_filter.mesh_object = mesh_object

        # Determine the primary brush's influence.
        center = primary_brush.center
        radius = primary_brush.radius
        vertex_filter.indices = octree.get_indices_in_box(center, radius)
        vertex_filter.coordinate_map = coordinate_map
        distance_map = vertex_filter.discard_outside_of_sphere(center, radius)
        primary_brush.indices = vertex_filter.indices

        # Only proceed if at least one vertex is within the primary brush's
        # influence.
        if primary_brush.indices:
            # Create the falloff map for the vertex indices that are within the
            # primary brush's influence.
            map_manager.map_ = distance_map
            map_manager.clip_domain(primary_brush.indices, 'RETAIN')
            primary_brush.falloff_map =\
                falloff_curve.get_falloff_map_from_distance_map(
                    distance_map, radius
                )

            # Calculate the primary brush's normal.
            primary_brush_falloff_map = primary_brush.falloff_map
            primary_brush_normal = primary_brush.normal
            normal = Vector((0, 0, 0))
            normal_sampling_radius = 0.333 * radius
            model_matrix = bpy.context.active_object.matrix_world
            vertices = bpy.context.active_object.data.vertices
            for vertex_index, distance in distance_map.items():
                # Only vertices within the normal sampling radius contribute to
                # the primary brush's normal.
                if distance <= normal_sampling_radius:
                    # Disregard vertices that face away from the primary
                    # brush's initial normal.
                    vertex_normal = model_matrix * (
                        vertices[vertex_index].normal
                    ).normalized()
                    if vertex_normal.dot(primary_brush_normal) > 0:
                        # Each vertex normal contributes in proportion to its
                        # falloff value.
                        normal += vertex_normal * (
                            primary_brush_falloff_map[vertex_index]
                        )
            normal.normalize()
            if normal.length_squared > 0:
                primary_brush.normal = normal.normalized()

            # Discard vertices facing away from the primary brush, if
            # necessary.
            if ignore_backfacing:
                vertex_filter.indices = primary_brush.indices
                vertex_filter.discard_backfacing(primary_brush.normal, 'WORLD')
                primary_brush.indices = vertex_filter.indices

        # Determine each derived brush's influence.
        self.update_derived()
        for brush in self.derived_brushes:
            # Determine which vertex indices are within the brush's influence.
            center = brush.center
            radius = brush.radius
            vertex_filter.indices = octree.get_indices_in_box(center, radius)
            vertex_filter.coordinate_map = octree.coordinate_map
            distance_map =\
                vertex_filter.discard_outside_of_sphere(center, radius)
            if ignore_backfacing:
                vertex_filter.discard_backfacing(brush.normal, 'WORLD')
            brush.indices = vertex_filter.indices

            # Only proceed if at least one vertex is within the brush's
            # influence.
            if primary_brush.indices:
                # Create the falloff map for the vertex indices that are within
                # the brush's influence.
                map_manager.map_ = distance_map
                map_manager.clip_domain(brush.indices, 'RETAIN')
                brush.falloff_map =\
                    falloff_curve.get_falloff_map_from_distance_map(
                        distance_map, radius
                    )
    def execute(self, context):

        mesh = context.object.data

        mesh.use_auto_smooth = True
        bpy.ops.mesh.customdata_custom_splitnormals_clear()

        bm = bmesh.new()
        bm.from_mesh(mesh)
        bm.verts.ensure_lookup_table()

        nor_weighted = []
        for v in bm.verts:
            max_area = 0
            areas = {}
            for i, f in enumerate(v.link_faces):

                if f.smooth:
                    area = f.calc_area()
                    areas[i] = area

                    if area > max_area:
                        max_area = area

            normal = Vector()
            for i, f in enumerate(v.link_faces):
                if f.smooth:
                    perc = areas[i] / max_area
                    normal += perc * f.normal

            nor_weighted.extend(normal.normalized())

        bm.free()

        nor_list = [(0,)] * len(mesh.loops)
        for poly in mesh.polygons:

            l_s = poly.loop_start
            l_e = poly.loop_start + poly.loop_total - 1

            curr_l = l_s
            prev_l = l_e
            while curr_l <= l_e:

                curr_loop = mesh.loops[curr_l]
                prev_loop = mesh.loops[prev_l]

                # if at least one edge of this corner doesn't use sharp edge
                # apply calculated weighted normal
                if not mesh.edges[curr_loop.edge_index].use_edge_sharp or not mesh.edges[prev_loop.edge_index].use_edge_sharp:

                    curr_n = nor_weighted[curr_loop.vertex_index * 3:curr_loop.vertex_index * 3 + 3]
                    nor_list[curr_l] = curr_n

                else:

                    nor_list[curr_l] = curr_loop.normal

                prev_l = curr_l
                curr_l += 1

        bpy.ops.mesh.customdata_custom_splitnormals_add()
        mesh.normals_split_custom_set(nor_list)
        mesh.free_normals_split()

        return {'FINISHED'}
	def execute(self, context):
		influenceamount = abs(context.window_manager.vn_bendingratio)
		showselected = context.window_manager.vn_editselection
		selectByFace = context.window_manager.vn_editbyface
		
		maxdist = context.window_manager.normtrans_maxdist
		influencemult = 1.0 if (
			context.window_manager.vn_bendingratio > 0.0
		) else -1.0
		
		selectByFace = context.window_manager.vn_editbyface
		editselection = context.window_manager.vn_editselection
		
		if maxdist <= 0.0:
			maxdist = 8192.0
		if influenceamount > 0.0:
			destobj = context.active_object.data
			destdata = []
			newnormals = []
			
			destobj.calc_normals_split()
			
			vertslist = [[(v.co).copy(), v.select] for v in destobj.vertices]
			loopnorms_raw = [(l.normal).copy() for l in destobj.loops]
			
			loopcount = 0
			dfcount = 0
			for f in destobj.polygons:
				fvn = []
				fvco = []
				fvsel = []
				newnormals.append([])
				
				for v in f.vertices:
					fvco.append(vertslist[v][0].copy())
					fvn.append(loopnorms_raw[loopcount].copy())
					
					if showselected:
						if selectByFace:
							fvsel.append(f.select)
						else:
							fvsel.append(vertslist[v][1])
					else:
						fvsel.append(True)
					loopcount += 1
					
					newnormals[dfcount].append([])
				
				destdata.append([fvco,fvn,fvsel])
				
				dfcount += 1
			
			destobj.free_normals_split()
			
			del vertslist[:]
			del loopnorms_raw[:]
			
			selobjects = [obj.data for obj in context.selected_objects if obj.type == 'MESH']
			sourceverts = []
			
			foundobj = (len(selobjects) > 1)
			
			for objmesh in selobjects:
				if objmesh != destobj:
					fcount = 0
					lastdist = maxdist
					curdistv = Vector((0.0,0.0,0.0))
					tempv = Vector((0.0,0.0,0.0))
					curdist = 0.0
					
					if objmesh.use_auto_smooth:
						sourceverts = []
						
						objmesh.calc_normals_split()
						
						vertslist = [[(v.co).copy(), v.select] for v in objmesh.vertices]
						loopnorms_raw = [(l.normal).copy() for l in objmesh.loops]
						
						loopcount = 0
						
						for f in objmesh.polygons:
							fvn = []
							fvco = []
							fvsel = []
							
							for v in f.vertices:
								fvco.append(vertslist[v][0].copy())
								fvn.append(loopnorms_raw[loopcount].copy())
								
								if showselected:
									if selectByFace:
										fvsel.append(f.select)
									else:
										fvsel.append(vertslist[v][1])
								else:
									fvsel.append(True)
								loopcount += 1
							
							sourceverts.append([fvco,fvn,fvsel])
						
						objmesh.free_normals_split()
						
						del vertslist[:]
						del loopnorms_raw[:]
						
						if len(sourceverts) > 0:
							for f in destdata:
								for i in range(len(f[0])):
									lastdist = maxdist
									nearest = f[1][i].copy()
									
									if f[2][i]:
										for df in sourceverts:
											for j in range(len(df[0])):
												curdistv = f[0][i] - df[0][j]
												curdist = curdistv.magnitude
												if curdist < maxdist:
													if curdist < lastdist:
														nearest = df[1][j].copy()
														lastdist = curdist
										
										tempv = (
											((f[1][i] * (1.0 - influenceamount)) 
											+ (nearest * influenceamount))
											* influencemult
										).normalized()
										newnormals[fcount][i].append(tempv.copy())
									
									else:
										newnormals[fcount][i].append(f[1][i].copy())
								
								fcount += 1
							
							del sourceverts[:]
					else:
						sourceverts = [[],[],[]]
			
						for v in objmesh.vertices:
							sourceverts[0].append((v.co).copy())
							sourceverts[1].append((v.normal).copy())
							if showselected:
								sourceverts[2].append(v.select)
							else:
								sourceverts[2].append(True)
						
						if len(sourceverts) > 0:
							
							for f in destdata:
								for i in range(len(f[0])):
									lastdist = maxdist
									nearest = f[1][i].copy()
									
									if f[2][i]:
										for j in range(len(sourceverts[0])):
											curdistv = f[0][i] - sourceverts[0][j]
											curdist = curdistv.magnitude
											if curdist < maxdist:
												if curdist < lastdist:
													nearest = sourceverts[1][j].copy()
													lastdist = curdist
										
										tempv = (
											((f[1][i] * (1.0 - influenceamount)) 
											+ (nearest * influenceamount))
											* influencemult
										).normalized()
										newnormals[fcount][i].append(tempv.copy())
									
									else:
										newnormals[fcount][i].append(f[1][i].copy())
								
								fcount += 1
							
							del sourceverts[:]
			
			del destdata[:]
			del selobjects[:]
			
			if foundobj:
				procnormslist = []
				
				for i in range(len(newnormals)):
					procnormslist.append([])
					for j in range(len(newnormals[i])):
						tempv = Vector((0.0,0.0,0.0))
						if len(newnormals[i][j]) > 0:
							for v in newnormals[i][j]:
								tempv = tempv + v
							procnormslist[i].append(tempv.normalized())
				
				if (update_customnormals(destobj, procnormslist)):
					context.area.tag_redraw()
					context.scene.update()
				
			else:
				print('Need more than one object')
			
			del newnormals[:]
			
		else:
			print('No influence')
		
		return {'FINISHED'}
def noise(var=1):
    rand = Vector((r.gauss(0, 1), r.gauss(0, 1), r.gauss(0, 1)))
    vec = rand.normalized() * var
    return vec
	def execute(self, context):
		mesh = context.active_object.data
		
		mesh.update()
		mesh.calc_normals_split()
		
		# store old normals
		normslist = []
		loopnorms = [v.normal for v in mesh.loops]
		loopcount = 0
		for f in mesh.polygons:
			fvns = []
			for i in range(len(f.vertices)):
				fvns.append(loopnorms[loopcount].copy())
				loopcount += 1
			normslist.append(fvns)
		del loopnorms[:]
		
		# clear old normals
		emptynormslist = tuple(tuple((0,0,0)) for v in mesh.vertices)
		for e in mesh.edges:
			if e.use_edge_sharp:
				e.use_edge_sharp = False
		
		mesh.validate(clean_customdata=False)
		if mesh.use_auto_smooth:
			mesh.use_auto_smooth = False
		if mesh.show_edge_sharp:
			mesh.show_edge_sharp = False
		mesh.normals_split_custom_set_from_vertices(emptynormslist)
		mesh.free_normals_split()
		mesh.update()
		
		# gather old split normals
		rawnormslist = [[] for v in mesh.vertices]
		
		faceslist = [f for f in mesh.polygons]
		fcount = 0
		for f in faceslist:
			newfn = []
			vcount = 0
			for v in f.vertices:
				rawnormslist[v].append(normslist[fcount][vcount])
				vcount += 1
			fcount += 1
		
		# average split normals for new list
		procnormslist = []
		for vl in rawnormslist:
			tempv = Vector((0.0,0.0,0.0))
			for v in vl:
				tempv = tempv + v
			tempv = tempv.normalized()
			procnormslist.append(tempv)
		
		vertslist = [v for v in mesh.vertices]
		vcount = 0
		for v in vertslist:
			v.normal = procnormslist[vcount]
			vcount += 1
		
		del rawnormslist[:]
		del procnormslist[:]
		del faceslist[:]
		del vertslist[:]
		
		return {'FINISHED'}
 def getNormalizedVector(sefl, vector):
     v = Vector(vector)
     return v.normalized()
def main(context,
         island_margin,
         projection_limit,
         user_area_weight,
         ):
    global USER_FILL_HOLES
    global USER_FILL_HOLES_QUALITY
    global USER_STRETCH_ASPECT
    global USER_ISLAND_MARGIN
    
    from math import cos
    import time

    global dict_matrix
    dict_matrix = {}


    # Constants:
    # Takes a list of faces that make up a UV island and rotate
    # until they optimally fit inside a square.
    global ROTMAT_2D_POS_90D
    global ROTMAT_2D_POS_45D
    global RotMatStepRotation
    main_consts()

    # Create the variables.
    USER_PROJECTION_LIMIT = projection_limit
    USER_ONLY_SELECTED_FACES = True
    USER_SHARE_SPACE = 1 # Only for hole filling.
    USER_STRETCH_ASPECT = 1 # Only for hole filling.
    USER_ISLAND_MARGIN = island_margin # Only for hole filling.
    USER_FILL_HOLES = 0
    USER_FILL_HOLES_QUALITY = 50 # Only for hole filling.
    USER_VIEW_INIT = 0 # Only for hole filling.
    
    is_editmode = (context.active_object.mode == 'EDIT')
    if is_editmode:
        obList =  [ob for ob in [context.active_object] if ob and ob.type == 'MESH']
    else:
        obList =  [ob for ob in context.selected_editable_objects if ob and ob.type == 'MESH']
        USER_ONLY_SELECTED_FACES = False

    if not obList:
        raise Exception("error, no selected mesh objects")

    # Reuse variable
    if len(obList) == 1:
        ob = "Unwrap %i Selected Mesh"
    else:
        ob = "Unwrap %i Selected Meshes"

    # HACK, loop until mouse is lifted.
    '''
    while Window.GetMouseButtons() != 0:
        time.sleep(10)
    '''

#~ XXX	if not Draw.PupBlock(ob % len(obList), pup_block):
#~ XXX		return
#~ XXX	del ob

    # Convert from being button types

    USER_PROJECTION_LIMIT_CONVERTED = cos(USER_PROJECTION_LIMIT * DEG_TO_RAD)
    USER_PROJECTION_LIMIT_HALF_CONVERTED = cos((USER_PROJECTION_LIMIT/2) * DEG_TO_RAD)


    # Toggle Edit mode
    is_editmode = (context.active_object.mode == 'EDIT')
    if is_editmode:
        bpy.ops.object.mode_set(mode='OBJECT')
    # Assume face select mode! an annoying hack to toggle face select mode because Mesh doesn't like faceSelectMode.

    if USER_SHARE_SPACE:
        # Sort by data name so we get consistent results
        obList.sort(key = lambda ob: ob.data.name)
        collected_islandList= []

#XXX	Window.WaitCursor(1)

    time1 = time.time()

    # Tag as False so we don't operate on the same mesh twice.
#XXX	bpy.data.meshes.tag = False
    for me in bpy.data.meshes:
        me.tag = False


    for ob in obList:
        me = ob.data

        if me.tag or me.library:
            continue

        # Tag as used
        me.tag = True

        if not me.uv_textures: # Mesh has no UV Coords, don't bother.
            me.uv_textures.new()

        uv_layer = me.uv_layers.active.data
        me_verts = list(me.vertices)

        if USER_ONLY_SELECTED_FACES:
            meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons) if f.select]
        else:
            meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons)]

        if not meshFaces:
            continue

#XXX		Window.DrawProgressBar(0.1, 'SmartProj UV Unwrapper, mapping "%s", %i faces.' % (me.name, len(meshFaces)))

        # =======
        # Generate a projection list from face normals, this is meant to be smart :)

        # make a list of face props that are in sync with meshFaces
        # Make a Face List that is sorted by area.
        # meshFaces = []

        # meshFaces.sort( lambda a, b: cmp(b.area , a.area) ) # Biggest first.
        meshFaces.sort(key=lambda a: -a.area)

        # remove all zero area faces
        while meshFaces and meshFaces[-1].area <= SMALL_NUM:
            # Set their UV's to 0,0
            for uv in meshFaces[-1].uv:
                uv.zero()
            meshFaces.pop()

        # Smallest first is slightly more efficient, but if the user cancels early then its better we work on the larger data.

        # Generate Projection Vecs
        # 0d is   1.0
        # 180 IS -0.59846


        # Initialize projectVecs
        if USER_VIEW_INIT:
            # Generate Projection
            projectVecs = [Vector(Window.GetViewVector()) * ob.matrix_world.inverted().to_3x3()] # We add to this along the way
        else:
            projectVecs = []

        newProjectVec = meshFaces[0].no
        newProjectMeshFaces = []	# Popping stuffs it up.


        # Pretend that the most unique angle is ages away to start the loop off
        mostUniqueAngle = -1.0

        # This is popped
        tempMeshFaces = meshFaces[:]



        # This while only gathers projection vecs, faces are assigned later on.
        while 1:
            # If theres none there then start with the largest face

            # add all the faces that are close.
            for fIdx in range(len(tempMeshFaces)-1, -1, -1):
                # Use half the angle limit so we don't overweight faces towards this
                # normal and hog all the faces.
                if newProjectVec.dot(tempMeshFaces[fIdx].no) > USER_PROJECTION_LIMIT_HALF_CONVERTED:
                    newProjectMeshFaces.append(tempMeshFaces.pop(fIdx))

            # Add the average of all these faces normals as a projectionVec
            averageVec = Vector((0.0, 0.0, 0.0))
            if user_area_weight == 0.0:
                for fprop in newProjectMeshFaces:
                    averageVec += fprop.no
            elif user_area_weight == 1.0:
                for fprop in newProjectMeshFaces:
                    averageVec += fprop.no * fprop.area
            else:
                for fprop in newProjectMeshFaces:
                    averageVec += fprop.no * ((fprop.area * user_area_weight) + (1.0 - user_area_weight))

            if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN
                projectVecs.append(averageVec.normalized())


            # Get the next vec!
            # Pick the face thats most different to all existing angles :)
            mostUniqueAngle = 1.0 # 1.0 is 0d. no difference.
            mostUniqueIndex = 0 # dummy

            for fIdx in range(len(tempMeshFaces)-1, -1, -1):
                angleDifference = -1.0 # 180d difference.

                # Get the closest vec angle we are to.
                for p in projectVecs:
                    temp_angle_diff= p.dot(tempMeshFaces[fIdx].no)

                    if angleDifference < temp_angle_diff:
                        angleDifference= temp_angle_diff

                if angleDifference < mostUniqueAngle:
                    # We have a new most different angle
                    mostUniqueIndex = fIdx
                    mostUniqueAngle = angleDifference

            if mostUniqueAngle < USER_PROJECTION_LIMIT_CONVERTED:
                #print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces)
                # Now weight the vector to all its faces, will give a more direct projection
                # if the face its self was not representative of the normal from surrounding faces.

                newProjectVec = tempMeshFaces[mostUniqueIndex].no
                newProjectMeshFaces = [tempMeshFaces.pop(mostUniqueIndex)]


            else:
                if len(projectVecs) >= 1: # Must have at least 2 projections
                    break


        # If there are only zero area faces then its possible
        # there are no projectionVecs
        if not len(projectVecs):
            Draw.PupMenu('error, no projection vecs where generated, 0 area faces can cause this.')
            return

        faceProjectionGroupList =[[] for i in range(len(projectVecs)) ]

        # MAP and Arrange # We know there are 3 or 4 faces here

        for fIdx in range(len(meshFaces)-1, -1, -1):
            fvec = meshFaces[fIdx].no
            i = len(projectVecs)

            # Initialize first
            bestAng = fvec.dot(projectVecs[0])
            bestAngIdx = 0

            # Cycle through the remaining, first already done
            while i-1:
                i-=1

                newAng = fvec.dot(projectVecs[i])
                if newAng > bestAng: # Reverse logic for dotvecs
                    bestAng = newAng
                    bestAngIdx = i

            # Store the area for later use.
            faceProjectionGroupList[bestAngIdx].append(meshFaces[fIdx])

        # Cull faceProjectionGroupList,


        # Now faceProjectionGroupList is full of faces that face match the project Vecs list
        for i in range(len(projectVecs)):
            # Account for projectVecs having no faces.
            if not faceProjectionGroupList[i]:
                continue

            # Make a projection matrix from a unit length vector.
            MatQuat = VectoQuat(projectVecs[i])

            # Get the faces UV's from the projected vertex.
            for f in faceProjectionGroupList[i]:
                f_uv = f.uv
                for j, v in enumerate(f.v):
                    # XXX - note, between mathutils in 2.4 and 2.5 the order changed.
                    f_uv[j][:] = (MatQuat * v.co).xy


        if USER_SHARE_SPACE:
            # Should we collect and pack later?
            islandList = getUvIslands(faceProjectionGroupList, me)
            collected_islandList.extend(islandList)

        else:
            # Should we pack the islands for this 1 object?
            islandList = getUvIslands(faceProjectionGroupList, me)
            packIslands(islandList)


        # update the mesh here if we need to.

    # We want to pack all in 1 go, so pack now
    if USER_SHARE_SPACE:
#XXX        Window.DrawProgressBar(0.9, "Box Packing for all objects...")
        packIslands(collected_islandList)

    print("Smart Projection time: %.2f" % (time.time() - time1))
    # Window.DrawProgressBar(0.9, "Smart Projections done, time: %.2f sec" % (time.time() - time1))

    if is_editmode:
        bpy.ops.object.mode_set(mode='EDIT')

    dict_matrix.clear()
def generate_newnormals(self, context):
    genmode = context.window_manager.vn_genmode
    me = context.active_object.data
    bm = bmesh.new()

    if context.mode == 'EDIT_MESH':
        bm = bmesh.from_edit_mesh(me)
    else:
        bm.from_mesh(me)

    me.update()

    faces_list = [f for f in bm.faces]
    verts_list = [v for v in bm.verts]

    # DEFAULT: Blender default
    if (genmode == 'DEFAULT'):
        wasobjmode = (context.mode == 'OBJECT')

        if wasobjmode:
            bpy.ops.object.mode_set(mode='EDIT')
            bm = bmesh.from_edit_mesh(me)
            me.update()
            faces_list = [f for f in bm.faces]
            verts_list = [v for v in bm.verts]

        bpy.ops.mesh.normals_make_consistent()

        if context.window_manager.edit_splitnormals:
            normals_data.cust_normals_ppoly.clear()
            for i in range(len(faces_list)):
                faceverts = [v for v in faces_list[i].verts]
                normals_data.cust_normals_ppoly.append([])
                for j in range(len(faceverts)):
                    normals_data.cust_normals_ppoly[len(normals_data.cust_normals_ppoly) - 1].append(faceverts[j].normal.copy())
        else:
            normals_data.cust_normals_pvertex.clear()
            for i in range(len(verts_list)):
                normals_data.cust_normals_pvertex.append(verts_list[i].normal.copy())

        if wasobjmode:
            bpy.ops.object.mode_set(mode='OBJECT')

    # UPVECT: custom direction
    elif (genmode == 'UPVECT'):
        if context.window_manager.edit_splitnormals:
            if context.window_manager.vn_genselectiononly:
                for i in range(len(normals_data.cust_normals_ppoly)):
                    for j in range(len(normals_data.cust_normals_ppoly[i])):
                        if faces_list[i].verts[j].select:
                            normals_data.cust_normals_ppoly[i][j] = Vector(context.window_manager.vn_dirvector)
            else:
                for i in range(len(normals_data.cust_normals_ppoly)):
                    for j in range(len(normals_data.cust_normals_ppoly[i])):
                        normals_data.cust_normals_ppoly[i][j] = Vector(context.window_manager.vn_dirvector)
        else:
            if context.window_manager.vn_genselectiononly:
                for i in range(len(verts_list)):
                    if verts_list[i].select:
                        normals_data.cust_normals_pvertex[i] = Vector(context.window_manager.vn_dirvector)
            else:
                for i in range(len(verts_list)):
                    normals_data.cust_normals_pvertex[i] = Vector(context.window_manager.vn_dirvector)

    # BENT: Bent from point (3D cursor)
    elif (genmode == 'BENT'):
        cursorloc = context.scene.cursor_location
        if context.window_manager.edit_splitnormals:
            if context.window_manager.vn_genselectiononly:
                for i in range(len(normals_data.cust_normals_ppoly)):
                    for j in range(len(normals_data.cust_normals_ppoly[i])):
                        if not (faces_list[i].hide) and faces_list[i].select:
                            tempv = Vector(faces_list[i].verts[j].co) - cursorloc
                            tempv = tempv.normalized()
                            normals_data.cust_normals_ppoly[i][j] = tempv.copy()
            else:
                for i in range(len(faces_list)):
                    for j in range(len(faces_list[i].verts)):
                        tempv = Vector(vd.vpos) - cursorloc
                        tempv = tempv.normalized()
                        normals_data.cust_normals_ppoly[i][j] = tempv.copy()
        else:
            if context.window_manager.vn_genselectiononly:
                for i in range(len(verts_list)):
                    if verts_list[i].select:
                        tempv = Vector(verts_list[i].co) - cursorloc
                        tempv = tempv.normalized()
                        tempv = (normals_data.cust_normals_pvertex[i] * (1.0 - context.window_manager.vn_genbendingratio)) + (tempv * (context.window_manager.vn_genbendingratio))
                        normals_data.cust_normals_pvertex[i] = tempv
            else:
                for i in range(len(verts_list)):
                    tempv = Vector(verts_list[i].co) - cursorloc
                    tempv = tempv.normalized()
                    tempv = (normals_data.cust_normals_pvertex[i] * (1.0 - context.window_manager.vn_genbendingratio)) + (tempv * (context.window_manager.vn_genbendingratio))
                    normals_data.cust_normals_pvertex[i] = tempv

    # G_FOLIAGE: combination of bent and up-vector for ground foliage
    elif (genmode == 'G_FOLIAGE'):
        ignorehidden = context.window_manager.vn_genignorehidden
        cursorloc = Vector(context.window_manager.vn_centeroffset)
        if context.window_manager.edit_splitnormals:
            for i in range(len(faces_list)):
                ignoreface = False
                if ignorehidden:
                    if faces_list[i].hide:
                        ignoreface = True
                for j in range(len(faces_list[i].verts)):
                    if faces_list[i].verts[j].select:
                        if not ignoreface:
                            normals_data.cust_normals_ppoly[i][j] = Vector((0.0, 0.0, 1.0))
                    else:
                        if not ignoreface:
                            tempv = faces_list[i].verts[j].co - cursorloc
                            normals_data.cust_normals_ppoly[i][j] = tempv.normalized()
        else:
            for i in range(len(verts_list)):
                if ignorehidden:
                    if not verts_list[i].hide:
                        if verts_list[i].select:
                            normals_data.cust_normals_pvertex[i] = Vector((0.0, 0.0, 1.0))
                        else:
                            tempv = verts_list[i].co - cursorloc
                            normals_data.cust_normals_pvertex[i] = tempv.normalized()
                else:
                    if verts_list[i].select:
                        normals_data.cust_normals_pvertex[i] = Vector((0.0, 0.0, 1.0))
                    else:
                        tempv = verts_list[i].co - cursorloc
                        normals_data.cust_normals_pvertex[i] = tempv.normalized()

    # CUSTOM: generate for selected faces independently from mesh (or for the whole mesh)
    # - based on existing face nomals, so the mesh requires faces
    # - seems to be weighted by mesh topology when used in poly mode
    #   - number of intersecting edges on connected face influences the direction
    elif (genmode == 'CUSTOM'):
        if context.window_manager.edit_splitnormals:
            for i in range(len(faces_list)):
                f = faces_list[i]
                if context.window_manager.vn_genselectiononly:
                    if f.select:
                        for j in range(len(f.verts)):
                            fncount = 0
                            tempfvect = Vector((0.0, 0.0, 0.0))
                            if f.verts[j].select:
                                for vf in f.verts[j].link_faces:
                                    if vf.select:
                                        fncount += 1
                                        tempfvect = tempfvect + vf.normal
                                if fncount > 0:
                                    normals_data.cust_normals_ppoly[i][j] = (tempfvect / float(fncount)).normalized()
                else:
                    for j in range(len(f.verts)):
                        fncount = len(f.verts[j].link_faces)
                        tempfvect = Vector((0.0, 0.0, 0.0))
                        for vf in f.verts[j].link_faces:
                            tempfvect = tempfvect + vf.normal
                        normals_data.cust_normals_ppoly[i][j] = (tempfvect / float(fncount)).normalized()
        else:
            for i in range(len(verts_list)):
                v = verts_list[i]
                if context.window_manager.vn_genselectiononly:
                    if v.select:
                        fncount = 0
                        tempfvect = Vector((0.0, 0.0, 0.0))
                        for j in range(len(v.link_faces)):
                            if v.link_faces[j].select:
                                fncount += 1
                                tempfvect = tempfvect + v.link_faces[j].normal
                        if fncount > 0:
                            normals_data.cust_normals_pvertex[i] = (tempfvect / float(fncount)).normalized()
                else:
                    fncount = len(v.link_faces)
                    tempfvect = Vector((0.0, 0.0, 0.0))
                    for j in range(len(v.link_faces)):
                        tempfvect = tempfvect + v.link_faces[j].normal
                    normals_data.cust_normals_pvertex[i] = (tempfvect / float(fncount)).normalized()

    save_normalsdata(context)

    if (hasattr(context.active_object.data, "define_normals_split_custom") or not context.window_manager.edit_splitnormals) and context.window_manager.vn_settomeshongen:
        set_meshnormals(context)