Esempio n. 1
0
 def to_point(self, centers, falloff):
     n = len(centers)
     if n == 1:
         sfield = SvScalarFieldPointDistance(centers[0], falloff=falloff)
         vfield = SvVectorFieldPointDistance(centers[0], falloff=falloff)
     elif self.point_mode == 'AVG':
         sfields = [SvScalarFieldPointDistance(center, falloff=falloff) for center in centers]
         sfield = SvMergedScalarField('AVG', sfields)
         vfields = [SvVectorFieldPointDistance(center, falloff=falloff) for center in centers]
         vfield = SvAverageVectorField(vfields)
     elif self.point_mode == 'MIN':
         kdt = kdtree.KDTree(len(centers))
         for i, v in enumerate(centers):
             kdt.insert(v, i)
         kdt.balance()
         vfield = SvKdtVectorField(kdt=kdt, falloff=falloff)
         sfield = SvKdtScalarField(kdt=kdt, falloff=falloff)
     else: # SEP
         sfield = [SvScalarFieldPointDistance(center, falloff=falloff) for center in centers]
         vfield = [SvVectorFieldPointDistance(center, falloff=falloff) for center in centers]
     return vfield, sfield
Esempio n. 2
0
    def match_raycast_vertex(self):
        self.bm = bmesh.new()
        self.bm.from_mesh(self.obj_t.data)
        self.bm.verts.ensure_lookup_table()
        self.bm.edges.ensure_lookup_table()
        self.bm.faces.ensure_lookup_table()

        bmesh.ops.remove_doubles(self.bm, verts=list(self.bm.verts), dist=3)

        size = len(self.bm.verts)
        kd = kdtree.KDTree(size)

        for i, vtx in enumerate(self.bm.verts):
            v = Vector((vtx.co.x, vtx.co.y, 0.0))
            kd.insert(v, i)
        kd.balance()

        plane = bpy.data.objects['Plane.001']
        self.bm.verts.ensure_lookup_table()
        self.bm.edges.ensure_lookup_table()
        self.bm.faces.ensure_lookup_table()

        for p in plane.data.vertices:
            wp = plane.matrix_world @ p.co
            lp = self.obj_t.matrix_world.inverted() @ wp

            #BL_DEBUG.set_mark(self.obj_t.matrix_world @ location)
            #BL_DEBUG.set_mark(plane.matrix_world @ p.co)
            location = Vector((lp.x, lp.y, 0.0))
            co, index, dist = kd.find(location)  # dist is the distance
            #print("Found", co, index, dist)
            #BL_DEBUG.set_mark(self.obj_t.matrix_world @ co)
            self.bm.verts[index].co[2] = lp.z  ## translated coords

            # tune this. There are more space (2-4m)
            if dist > 0.4:
                self.bm.verts[index].co[0] = lp.x  ## translated coords
                self.bm.verts[index].co[1] = lp.y  ## translated coords
        self.update_bm(freeit=True)
Esempio n. 3
0
def object_list2(objects, active=0):
    """
	Return an approximate shortest path through objects starting at the
	active index using the nearest neighbor heuristic.
	"""

    s = time()

    # calculate a kd tree to quickly answer nearest neighbor queries
    kd = kdtree.KDTree(len(objects))
    for i, ob in enumerate(objects):
        kd.insert(ob.location, i)
    kd.balance()

    current = objects[active]
    chain = [current]  # we start at the chosen object
    added = {active}
    for i in range(1, len(objects)):  # we know how many objects to add
        # when looking for the nearest neighbor we start with two neigbors
        # (because we include the object itself in the search) and if
        # the other neigbors is not yet in the chain we add it, otherwise
        # we expand our search to a maximum of the total number of objects
        for n in range(2, len(objects)):
            neighbors = {
                index
                for _, index, _ in kd.find_n(current.location, n)
            }
            neighbors -= added
            if neighbors:  # strictly speaking we shoudl assert that len(neighbors) == 1
                chain.extend(objects[i] for i in neighbors)
                added |= neighbors
                break
        current = chain[-1]

    print("{n:d} objects {t:.1f}s".format(t=time() - s, n=len(objects)))

    return chain
Esempio n. 4
0
def mirror_l_to_r_back():
    bpy.ops.object.mode_set(mode = 'OBJECT')
    obj = bpy.context.active_object
    mesh = obj.data

    size = len(mesh.vertices)
    kd = kdtree.KDTree(size)

    rside_indices = [i for i,v in enumerate(mesh.vertices) if v.co.x < 0]
    lside_pos = [[i,(-v.co.x , v.co.y , v.co.z )] for i,v in enumerate(mesh.vertices) if v.co.x < 0]

    # selectedVtxIndex = set([v.index for v in obj.data.vertices if v.select])
    # print(selectedVtxIndex)

    print(lside_pos)
    for i, v in enumerate(mesh.vertices):
        kd.insert(v.co, i)

    kd.balance()

    #co_find = (0.0, 0.0, 0.0)

    bpy.ops.object.mode_set(mode = 'EDIT')
    bpy.ops.mesh.select_mode(type="VERT")
    bpy.ops.mesh.select_all(action = 'DESELECT')
    bpy.ops.object.mode_set(mode = 'OBJECT')

    for p in lside_pos:
        co, index, dist = kd.find( p[1] )
        print("Close to center:",p[0],':', co, index, dist)
        obj.data.vertices[p[0]].co = (-co.x,co.y,co.z)


    # for i in rside_indices:
    #     mesh.vertices[i].select = True
        #obj.data.vertices[i].co.x = 2.0
    bpy.ops.object.mode_set(mode = 'EDIT')
Esempio n. 5
0
def sv_main(v=[[]], mdist=0.4):

    in_sockets = [
        ['v', 'verts', v],
        ['s', 'mdist', mdist]
    ]

    e = []

    if v and v[0]:

        v = v[0]
        # make kd tree
        # documentation mathutils.kdtree.html
        size = len(v)
        kd = kdtree.KDTree(size)

        for i, vtx in enumerate(v):
            kd.insert(Vector(vtx), i)
        kd.balance()

        # makes edges
        for i, vtx in enumerate(v):
            num_edges = 0
            for (co, index, dist) in kd.find_range(vtx, mdist):
                if i == index or (num_edges > 2):
                    continue
                e.append([i, index])
                num_edges += 1

    # out boilerplate
    out_sockets = [
        ['s', 'Edges', [e]]
    ]

    return in_sockets, out_sockets
Esempio n. 6
0
    def by_sphere(self, vertices, edges, faces):
        radius = self.inputs['Radius'].sv_get(default=[1.0])[0][0]
        centers = self.inputs['Center'].sv_get()[0]

        if len(centers) == 1:
            center = centers[0]
            out_verts_mask = [((Vector(v) - Vector(center)).length <= radius) for v in vertices]
        else:
            # build KDTree
            tree = kdtree.KDTree(len(centers))
            for i, v in enumerate(centers):
                tree.insert(v, i)
            tree.balance()

            out_verts_mask = []
            for vertex in vertices:
                _, _, rho = tree.find(vertex)
                mask = rho <= radius
                out_verts_mask.append(mask)

        out_edges_mask = self.select_edges_by_verts(out_verts_mask, edges)
        out_faces_mask = self.select_faces_by_verts(out_verts_mask, faces)

        return out_verts_mask, out_edges_mask, out_faces_mask
Esempio n. 7
0
    def init_guess():
        us = np.linspace(u_min, u_max, num=init_samples)
        vs = np.linspace(v_min, v_max, num=init_samples)
        us, vs = np.meshgrid(us, vs)
        us = us.flatten()
        vs = vs.flatten()

        points = surface.evaluate_array(us, vs).tolist()

        kdt = kdtree.KDTree(len(us))
        for i, v in enumerate(points):
            kdt.insert(v, i)
        kdt.balance()

        us_out = []
        vs_out = []
        nearest_out = []
        for point_from in points_from:
            nearest, i, distance = kdt.find(point_from)
            us_out.append(us[i])
            vs_out.append(vs[i])
            nearest_out.append(tuple(nearest))

        return us_out, vs_out, nearest_out
Esempio n. 8
0
    def process(self):
        if not any(output.is_linked for output in self.outputs):
            return

        vertices_s = self.inputs['Vertices'].sv_get(default=[[]])
        masks_s = self.inputs['Mask'].sv_get()
        radius_s = self.inputs['Radius'].sv_get()

        out_coeffs = []
        meshes = match_long_repeat([vertices_s, masks_s, radius_s])
        for vertices, masks, radius in zip(*meshes):
            fullList(masks, len(vertices))

            if isinstance(radius, list) and isinstance(radius[0],
                                                       (int, float)):
                radius = radius[0]

            # build KDTree
            base = [v for v, mask in zip(vertices, masks) if mask]
            tree = kdtree.KDTree(len(base))
            for i, v in enumerate(base):
                tree.insert(v, i)
            tree.balance()

            coeffs = []
            for vertex, mask in zip(vertices, masks):
                if mask:
                    coef = 1.0
                else:
                    _, _, rho = tree.find(vertex)
                    coef = self.falloff(radius, rho)
                coeffs.append(coef)

            out_coeffs.append(coeffs)

        self.outputs['Coeffs'].sv_set(out_coeffs)
def creat_tree(line):
    # Create KDTree for line
    tree = kdtree.KDTree(len(line))
    [tree.insert(p, i) for i, p in enumerate(line)]
    tree.balance()
    return tree
def Terraform(index, startY, startX, distY, distX, endY, endX, level, radius,
              lenY, lenX, falloff, vertY, vertX, realY, realX, m, terraKey,
              exclude):

    index = eval(index)
    dy = index[0] - startY
    dx = index[1] - startX
    localPos = (200 * dy, 200 * dx)
    worldPos = Vector([realX + localPos[1], realY + localPos[0], 0])
    cellDict = core.world["cellDict"]

    worldKey = (dx + realX, dy + realY)
    if worldKey not in cellDict:
        cellDict[worldKey] = {"heightMap": [], "objects": [], "init": False}

    file = gamepath + "\\dsm\\cache\\landmass\\%s\\exclude.txt" % (terraKey)
    exclude = eval(exclude)
    if str(index) in exclude:
        return False

    cvi = core.grid["verts"][vertY, vertX][0]
    origin = Vector(m.getVertex(0, cvi).getXYZ()[0:2]) + Vector([realX, realY])

    try:
        f = np.load(gamepath + "\\dsm\\cache\\landmass\\%s\\%s.npy" %
                    (terraKey, str(index)))

    except:

        kd = kdtree.KDTree(41 * 41)
        f = np.full((41, 41), abs(radius * level))
        terraLoop1_ufunc(kd, terra_i, worldPos.x, worldPos.y)

        kd.balance()
        near = kd.find_range(Vector([realX, realY, 0]), radius**2)

        doLenAdjust = lenX != lenY

        for n in near:
            co, kd_index, dist = n
            point = ps[kd_index]

            if doLenAdjust:

                if min(lenX, lenY) == lenX:
                    distX = np.linalg.norm(
                        Vector([co.x, 0, 0]) - Vector([origin.x, 0, 0]))
                    dist += distX * (16 * falloff)

                elif min(lenX, lenY) == lenY:
                    distY = np.linalg.norm(
                        Vector([0, co.y, 0]) - Vector([0, origin.y, 0]))
                    dist += distY * (16 * falloff)

            e = max(0, dist)
            new_f = getHeightFactor(level, radius, falloff, e)
            if abs(new_f) > 0: f[i_list[kd_index]] = e

        if len(f[f != abs(radius * level)].tolist()) > 0:
            np.save(
                gamepath + "\\dsm\\cache\\landmass\\%s\\%s.npy" %
                (terraKey, str(index)), f)
        else:
            exclude = open(file, "a")
            exclude.write(str(index) + "\n")

    if len(f[f != abs(radius * level)].tolist()) > 0:
        cellDict[worldKey]["heightMap"].append(
            [vertY, vertX, radius, level, falloff, f, (lenX, lenY)])

    return True
Esempio n. 11
0
    def execute(self, context):
        depsgraph = bpy.context.depsgraph
        ob = bpy.context.active_object
        obj_eval = depsgraph.objects.get(ob.name, None)

        # particleObj = context.active_object
        particleObj = obj_eval
        if bpy.context.active_object.particle_systems is None:  # create new one
            self.report({'INFO'}, 'No active Particle Hair System found!')
            return {"CANCELLED"}
        index = particleObj.particle_systems.active_index
        psys_active = particleObj.particle_systems[index]
        if psys_active.settings.type != 'HAIR':  # create new one
            self.report({'INFO'},
                        'Active Particle System is not Hair type! Cancelling')
            return {"CANCELLED"}
        pointsList_hair = []
        context.scene.update()
        if len(psys_active.particles) == 0:  # require more that three strands
            self.report({'INFO'},
                        'Active Particle System has zero strands! Cancelling')
            return {"CANCELLED"}
        diagonal = sqrt(
            pow(particleObj.dimensions[0], 2) +
            pow(particleObj.dimensions[1], 2) +
            pow(particleObj.dimensions[2], 2))  # to normalize some values
        for particle in psys_active.particles:  # for strand point
            pointsList_hair.append([
                hair_key.co for hair_key in particle.hair_keys
            ])  # DONE: exclude duplicates if first strand[0] in list already
        if len(psys_active.particles
               ) == 1:  #create two fake strands so that barycentric works
            pointsList_hair.append([
                x.xyz + Vector((0.01 * diagonal, 0, 0))
                for x in pointsList_hair[0]
            ])
            pointsList_hair.append([
                x.xyz + Vector((0, 0.01 * diagonal, 0))
                for x in pointsList_hair[0]
            ])
        elif len(psys_active.particles
                 ) == 2:  #create one fake strands so that barycentric works
            pointsList_hair.append([
                x.xyz + Vector((0.01 * diagonal, 0, 0))
                for x in pointsList_hair[0]
            ])
        pointsList_uniq = []
        [
            pointsList_uniq.append(x) for x in pointsList_hair
            if x not in pointsList_uniq
        ]  #removing doubles (can cause zero size tris)

        #same_point_count cos barycentric transform requires it
        pointsList = interpol_Catmull_Rom(
            pointsList_uniq,
            self.t_in_y,
            uniform_spacing=True,
            same_point_count=True)  # just gives smoother result on borders

        searchDistance = 100 * diagonal
        parentRoots = [strand[0]
                       for strand in pointsList]  # first point of roots
        #create nnew Part Sytem with uniform points
        pointsChildRoots = self.createUniformParticleSystem(
            context, self.childCount, self.PlacementJittering,
            self.Seed)  # return child part roots positions

        kd = kdtree.KDTree(len(parentRoots))
        for i, root in enumerate(parentRoots):
            kd.insert(root, i)
        kd.balance()
        sourceSurface_BVHT = BVHTree.FromObject(particleObj, context.depsgraph)
        childStrandsPoints = []  #will contain strands with child points
        childStrandRootNormals = []
        length_ver_group_index = -1
        vertex_group_length_name = psys_active.vertex_group_length
        if vertex_group_length_name:  # calc weight based on root point
            length_ver_group_index = particleObj.vertex_groups[
                vertex_group_length_name].index
        particleObjMesh = particleObj.to_mesh(context.depsgraph,
                                              apply_modifiers=True,
                                              calc_undeformed=False)
        seed(a=self.lenSeed, version=2)
        embed = self.embed * 0.04 * diagonal
        cpow = calc_power(self.noiseFalloff)
        cpowClump = calc_power(self.ClumpingFalloff)
        noiseFalloff = [pow(i / self.t_in_y, cpow) for i in range(self.t_in_y)]
        ClumpFalloff = [
            pow((i + 1) / self.t_in_y, cpowClump) for i in range(self.t_in_y)
        ]

        for i, childRoot in enumerate(
                pointsChildRoots
        ):  #for each child find it three parents and genereate strands by barycentric transform
            snappedPoint, normalChildRoot, rootHitIndex, distance = sourceSurface_BVHT.find_nearest(
                childRoot, searchDistance)
            childStrandRootNormals.append(normalChildRoot)
            threeClosestParentRoots = kd.find_n(
                childRoot, 3)  #find three closes parent roots
            rootTri_co, ParentRootIndices, distances = zip(
                *threeClosestParentRoots)  #split it into 3 arrays
            sourceTri_BVHT = BVHTree.FromPolygons(
                rootTri_co, [(0, 1, 2)],
                all_triangles=True)  # [0,1,2] - polygon == vert indices list
            childRootSnapped, normalChildProjected, index, distance = sourceTri_BVHT.find_nearest(
                childRoot, searchDistance
            )  #snap generated child to parent triangle ares \normals are sometimes flipped
            childRootSnapped2, normalChildProjected2, index2, distance2 = sourceSurface_BVHT.find_nearest(
                childRootSnapped,
                searchDistance)  #this gives ok normals always

            lenWeight = 1
            if length_ver_group_index != -1:  # if vg exist
                averageWeight = 0
                for vertIndex in particleObjMesh.polygons[
                        rootHitIndex].vertices:  #DONE: check if work on mesh with modifiers
                    for group in particleObjMesh.vertices[vertIndex].groups:
                        if group.group == length_ver_group_index:
                            averageWeight += group.weight
                            break
                lenWeight = averageWeight / len(
                    particleObjMesh.polygons[rootHitIndex].vertices)
            ranLen = uniform(-self.RandomizeLengthMinus,
                             self.RandomizeLengthPlus)
            lenWeight *= (1 + ranLen)
            # diff = childRoot - childRootSnapped
            # mat_loc = Matrix.Translation(childRootSnapped)
            # matTriangleSpaceInv = mat_loc #* rotMatrix
            # matTriangleSpaceInv.invert()
            rotQuat = normalChildProjected2.rotation_difference(
                normalChildRoot)
            translationMatrix = Matrix.Translation(childRoot)
            rotMatrixRot = rotQuat.to_matrix().to_4x4()
            mat_sca = Matrix.Scale(lenWeight, 4)
            transformMatrix = translationMatrix @ rotMatrixRot
            strandPoints = []
            #for childRootSnapped points transform them from parent root triangles to parent next segment triangle t1,t2,t3
            # and compensate child snapping to root triangle from before
            for j, (t1, t2, t3) in enumerate(
                    zip(pointsList[ParentRootIndices[0]],
                        pointsList[ParentRootIndices[1]],
                        pointsList[ParentRootIndices[2]])):
                pointTransformed = barycentric_transform(
                    childRootSnapped, rootTri_co[0], rootTri_co[1],
                    rootTri_co[2], Vector(t1), Vector(t2), Vector(t3))
                childInterpolatedPoint = transformMatrix @ mat_sca @ (
                    pointTransformed - childRootSnapped
                )  #rotate child strand to original pos (from before snapt)
                #do noise
                noise.seed_set(self.Seed + i)  # add seed per strand/ring ?
                noiseVectorPerStrand = noise.noise_vector(
                    childInterpolatedPoint * self.freq / diagonal,
                    noise_basis='PERLIN_ORIGINAL'
                ) * noiseFalloff[j] * self.noiseAmplitude * diagonal / 10
                # childInterpolatedPoint += noiseVectorPerStrand

                #do clumping
                diff = Vector(
                    t1
                ) - childInterpolatedPoint  # calculate distance to parent strand (first strand from trio)
                # point += noiseVectorPerStrand * noiseFalloff[j] * self.noiseAmplitude * diagonal / 10
                # childClumped = childInterpolatedPoint + ClumpFalloff[j] * self.Clumping * diff + noiseVectorPerStrand * (1-ClumpFalloff[j])
                childClumped = childInterpolatedPoint + ClumpFalloff[
                    j] * self.Clumping * diff + noiseVectorPerStrand * (
                        1 - ClumpFalloff[j] * self.Clumping)
                # childClumped = childInterpolatedPoint + noiseVectorPerStrand

                strandPoints.append(childClumped)
            # embeding roots
            diff = strandPoints[0] - strandPoints[1]
            diff.normalize()
            normalWeight = abs(diff.dot(normalChildRoot))
            strandPoints[0] += (
                diff * normalWeight - normalChildRoot * (1 - normalWeight)
            ) * embed  # do childStrandRootNormal to move it more into mesh surface
            childStrandsPoints.append(strandPoints)

        bpy.data.meshes.remove(particleObjMesh)
        # create the Curve Datablock
        curveData = bpy.data.curves.new(particleObj.name + '_curve',
                                        type='CURVE')

        splinePointsNp = np.array(childStrandsPoints, dtype=np.float32)
        if self.hairType != 'BEZIER':
            splinePointsNpOnes = np.ones(
                (len(childStrandsPoints), self.t_in_y, 4),
                dtype=np.float32)  # 4 coord x,y,z ,1
            splinePointsNpOnes[:, :, :-1] = splinePointsNp
            splinePointsNp = splinePointsNpOnes
        for strandPoints in splinePointsNp:  # for strand point
            curveLength = len(strandPoints)
            polyline = curveData.splines.new(self.hairType)
            if self.hairType == 'BEZIER':
                polyline.bezier_points.add(curveLength - 1)
            elif self.hairType == 'POLY' or self.hairType == 'NURBS':
                polyline.points.add(curveLength - 1)
            if self.hairType == 'NURBS':
                polyline.order_u = 3  # like bezier thing
                polyline.use_endpoint_u = True

            if self.hairType == 'BEZIER':
                # polyline.bezier_points.co = (x, y, z)
                polyline.bezier_points.foreach_set("co", strandPoints.ravel())
                polyline.bezier_points.foreach_set('handle_left_type', 'AUTO')
                polyline.bezier_points.foreach_set('handle_right_type', 'AUTO')
            else:
                polyline.points.foreach_set("co", strandPoints.ravel())
                # polyline.points[i].co = (x, y, z, 1)
        curveData.resolution_u = self.strandResU
        curveData.dimensions = '3D'
        # create Object
        curveOB = bpy.data.objects.new(particleObj.name + '_curve', curveData)
        curveOB.matrix_world = particleObj.matrix_world
        scn = context.scene
        scn.collection.objects.link(curveOB)
        curveOB.targetObjPointer = particleObj.name  # store source surface for snapping oper
        context.view_layer.objects.active = curveOB
        curveOB.select_set(True)
        # curveOB.data.show_normal_face = False
        if self.generateRibbons:
            bpy.ops.object.generate_ribbons(strandResU=self.strandResU,
                                            strandResV=self.strandResV,
                                            strandWidth=self.strandWidth,
                                            strandPeak=self.strandPeak,
                                            strandUplift=self.strandUplift,
                                            alignToSurface=self.alignToSurface)
            HT_OT_CurvesUVRefresh.uvCurveRefresh(curveOB)
            context.view_layer.objects.active = particleObj
        else:
            curveData.fill_mode = 'FULL'
            curveData.bevel_depth = 0.004 * diagonal
            curveData.bevel_resolution = 2
            bpy.ops.object.curve_taper(TipRadiusFalloff=self.RadiusFalloff,
                                       TipRadius=self.TipRadius,
                                       MainRadius=self.Radius)
        return {"FINISHED"}
Esempio n. 12
0
 def __init__(self, vertices):
     self.kdt = kdtree.KDTree(len(vertices))
     for i, v in enumerate(vertices):
         self.kdt.insert(v, i)
     self.kdt.balance()
     self.__description__ = "Voronoi"
Esempio n. 13
0
    def particle_hair_to_points_with_children(self, context):
        partsysMod = self.particleObj.particle_systems.active  # use last
        particle_id = self.particleObj.particle_systems.active_index  # use last
        particle_modal_settings = context.active_object.modal_hair.particle_system_modal_settings[
            particle_id]  # cos using self.particleObj gives random settings...
        diagonal = self.diagonal
        particle_count = len(partsysMod.particles)
        if particle_count == 0:  #require more that three strands
            return self.particle_hair_to_points(context)
        pointsList_hair = []

        coords = []
        global PARTICLE_CO  #cache strands for drawing
        strands_len = len(partsysMod.particles[0].hair_keys) - 1
        for strand in partsysMod.particles:  # for strand point
            pointsList_hair.append([
                hair_key.co for hair_key in strand.hair_keys
            ])  # DONE: exclude duplicates if first strand[0] in list already
            if context.active_object.modal_hair.drawStrands:
                for i, point in enumerate(
                        strand.hair_keys):  # create p1,p2,  p2,p3,  p3,p4
                    if i == 0 or i == strands_len:
                        coords.append((point.co[0], point.co[1], point.co[2]))
                    else:
                        coords.extend([(point.co[0], point.co[1], point.co[2]),
                                       (point.co[0], point.co[1], point.co[2])
                                       ])
            else:
                coords = [(0, 0, 0)]
        PARTICLE_CO = coords

        if particle_count == 1:  #create two fake strands so that barycentric works
            pointsList_hair.append([
                x.xyz + Vector((0.01 * diagonal, 0, 0))
                for x in pointsList_hair[0]
            ])
            pointsList_hair.append([
                x.xyz + Vector((0, 0.01 * diagonal, 0))
                for x in pointsList_hair[0]
            ])
        elif particle_count == 2:  #create one fake strands so that barycentric works
            pointsList_hair.append([
                x.xyz + Vector((0.01 * diagonal, 0, 0))
                for x in pointsList_hair[0]
            ])

        #TODO: damm it is slow - 0.3 sec - on 3333 particle mesh (while doing sinterpol is just 0.02 sec)
        #FIXED: it was here cos particles woudl fail on duplicates.... Fixed by removing duplis in init
        # pointsList_uniq = []
        # [pointsList_uniq.append(x) for x in pointsList_hair if x not in pointsList_uniq]  # removing doubles (can cause zero size tris)
        pointsList_uniq = pointsList_hair

        # same_point_count cos barycentric transform requires it
        pointsList = interpol_Catmull_Rom(
            pointsList_uniq,
            particle_modal_settings.t_in_y,
            uniform_spacing=False,
            same_point_count=True)  # just gives smoother result on borders
        searchDistance = 100 * diagonal
        parentRoots = [strand[0]
                       for strand in pointsList]  # first point of roots
        # create nnew Part Sytem with uniform points
        pointsChildRoots = HT_OT_RibbonsFromParticleHairChild.createUniformParticleSystem(
            context, particle_modal_settings.childCount,
            particle_modal_settings.PlacementJittering
        )  # return child part roots positions

        kd = kdtree.KDTree(len(parentRoots))
        for i, root in enumerate(parentRoots):
            kd.insert(root, i)
        kd.balance()
        sourceSurface_BVHT = self.sourceSurface_BVHT
        childStrandsPoints = []  # will contain strands with child points
        childStrandRootNormals = []
        seed(a=particle_modal_settings.lenSeed, version=2)
        for i, childRoot in enumerate(
                pointsChildRoots
        ):  # for each child find it three parents and genereate strands by barycentric transform
            snappedPoint, normalChildRoot, rootHitIndex, distance = sourceSurface_BVHT.find_nearest(
                childRoot, searchDistance)
            childStrandRootNormals.append(normalChildRoot)
            threeClosestParentRoots = kd.find_n(
                childRoot, 3)  # find three closes parent roots
            rootTri_co, ParentRootIndices, distances = zip(
                *threeClosestParentRoots)  # split it into 3 arrays
            sourceTri_BVHT = BVHTree.FromPolygons(
                rootTri_co, [(0, 1, 2)],
                all_triangles=True)  # [0,1,2] - polygon == vert indices list
            childRootSnapped, normalChildProjected, index, distance = sourceTri_BVHT.find_nearest(
                childRoot, searchDistance
            )  # snap generated child to parent triangle ares \normals are sometimes flipped
            childRootSnapped2, normalChildProjected2, index2, distance2 = sourceSurface_BVHT.find_nearest(
                childRootSnapped,
                searchDistance)  # this gives ok normals always

            lenWeight = 1 + uniform(
                -particle_modal_settings.RandomizeLengthMinus,
                particle_modal_settings.RandomizeLengthPlus)
            rotQuat = normalChildProjected2.rotation_difference(
                normalChildRoot)
            translationMatrix = Matrix.Translation(childRoot)
            rotMatrixRot = rotQuat.to_matrix().to_4x4()
            mat_sca = Matrix.Scale(lenWeight, 4)
            transformMatrix = translationMatrix @ rotMatrixRot
            strandPoints = []
            # for childRootSnapped points transform them from parent root triangles to parent next segment triangle t1,t2,t3
            # and compensate child snapping to root triangle from before
            for j, (t1, t2, t3) in enumerate(
                    zip(pointsList[ParentRootIndices[0]],
                        pointsList[ParentRootIndices[1]],
                        pointsList[ParentRootIndices[2]])):
                pointTransformed = barycentric_transform(
                    childRootSnapped, rootTri_co[0], rootTri_co[1],
                    rootTri_co[2], Vector(t1), Vector(t2), Vector(t3))
                childInterpolatedPoint = transformMatrix @ mat_sca @ (
                    pointTransformed - childRootSnapped
                )  # rotate child strand to original pos (from before snapt)
                strandPoints.append(childInterpolatedPoint)
            childStrandsPoints.append(strandPoints)
        if particle_modal_settings.use_parent_strands:
            childStrandsPoints.extend(pointsList)
        return childStrandsPoints
Esempio n. 14
0
def create_u_core_vert_groups_vert_lists_2(bm, dimensions, margin, vert_locs,
                                           subdivs):
    """Create vertex group vertex lists for U core sides

    Args:
        bm (bmesh): bmesh
        dimensions (dict{
            leg_1_inner: float,
            leg_2_inner: float,
            base_height: float,
            height: float,
            x_inner: float,
            thickness: float,
            thickness_diff: float}): core dimensions
        margin (float): margin between textured and blank areas
        vert_locs (dict{
            Leg 1 Inner: list[Vector(3)]
            Leg 2 Inner: list[Vector(3)]
            Leg 1 Outer: list[Vector(3)]
            Leg 2 Outer: list[Vector(3)]
            Leg 1 End: list[Vector(3)]
            Leg 2 End: list[Vector(3)]
            End Wall Inner': list[Vector(3)]
            End Wall Outer': list[Vector(3)]}: vertex locations
        subdivs (dict{
            leg_1: int,
            leg_2: int,
            x: int,
            width: int,
            height: int}): subdivisions

    Returns:
        dict{
            Leg 1 Inner: list[BMVert],
            Leg 1 Outer: list[BMVert],
            Leg 2 Inner: list[BMVert],
            Leg 2 Outer: list[BMVert],
            Leg 1 Top: list[BMVert],
            Leg 2 Top: list[BMVert],
            Leg 1 Bottom: list[BMVert],
            Leg 2 Bottom: list[BMVert],
            Leg 1 End: list[BMVert],
            Leg 2 End: list[BMVert],
            End Wall Inner: list[BMVert],
            End Wall Outer: list[BMVert],
            End Wall Top: list[BMVert]
            End Wall Bottom: list[BMVert]}: Verts to assign to vert groups
    """
    height = dimensions['height']
    thickness_diff = dimensions['thickness_diff']
    thickness = dimensions['thickness']
    leg_1_inner_len = dimensions['leg_1_inner'] + (thickness_diff / 2)
    leg_2_inner_len = dimensions['leg_2_inner'] + (thickness_diff / 2)
    leg_1_outer_len = leg_1_inner_len + thickness
    leg_2_outer_len = leg_2_inner_len + thickness

    vert_groups = {}

    # create kdtree
    size = len(bm.verts)
    kd = kdtree.KDTree(size)

    for i, v in enumerate(bm.verts):
        kd.insert(v.co, i)

    kd.balance()

    # leg_sides
    leg_sides = {
        'Leg 1 Inner': (vert_locs['Leg 1 Inner'][::-1], leg_1_inner_len),
        'Leg 2 Inner': (vert_locs['Leg 2 Inner'], leg_2_inner_len),
        'Leg 1 Outer': (vert_locs['Leg 1 Outer'], leg_1_outer_len),
        'Leg 2 Outer': (vert_locs['Leg 2 Outer'][::-1], leg_2_outer_len)
    }

    for key, value in leg_sides.items():
        vert_groups[key] = select_verts_in_bounds(
            lbound=(value[0][0]),
            ubound=(value[0][-1][0], value[0][-1][1] + value[1],
                    value[0][-1][2] + height),
            buffer=margin / 2,
            bm=bm)

    end_wall_sides = {
        'End Wall Inner': vert_locs['End Wall Inner'],
        'End Wall Outer': vert_locs['End Wall Outer'][::-1]
    }

    # end_wall_sides
    for key, value in end_wall_sides.items():
        vert_groups[key] = select_verts_in_bounds(
            lbound=(value[0]),
            ubound=(value[-1][0], value[-1][1], value[-1][2] + height),
            buffer=margin / 2,
            bm=bm)

    # leg ends
    ends = {
        'Leg 1 End': vert_locs['Leg 1 End'],
        'Leg 2 End': vert_locs['Leg 2 End']
    }

    for key, value in ends.items():
        vert_groups[key] = select_verts_in_bounds(
            lbound=(value[0]),
            ubound=(value[1][0], value[1][1], value[1][2] + height),
            buffer=margin / 2,
            bm=bm)
    bm_deselect_all(bm)

    # bottom
    # leg 1
    inner_locs = vert_locs['Leg 1 Inner'][::-1]
    outer_locs = vert_locs['Leg 1 Outer']

    selected_verts = []
    i = 0
    while i < len(outer_locs) and i < len(inner_locs):
        v1_co, v1_index, dist = kd.find(inner_locs[i])
        v2_co, v2_index, dist = kd.find(outer_locs[i])

        bm.verts.ensure_lookup_table()
        v1 = bm.verts[v1_index]
        v2 = bm.verts[v2_index]

        nodes = bm_shortest_path(bm, v1, v2)
        node = nodes[v2]

        for e in node.shortest_path:
            e.select_set(True)
        bm.select_flush(True)

        verts = [v for v in bm.verts if v.select]
        selected_verts.extend(verts)
        i += 1

    vert_groups['Leg 1 Bottom'] = selected_verts
    bm_deselect_all(bm)

    # leg 2
    inner_locs = vert_locs['Leg 2 Inner'][::-1]
    outer_locs = vert_locs['Leg 2 Outer']

    selected_verts = []
    i = 0
    while i < len(inner_locs) and i < len(outer_locs):
        v1_co, v1_index, dist = kd.find(inner_locs[i])
        v2_co, v2_index, dist = kd.find(outer_locs[i])

        bm.verts.ensure_lookup_table()
        v1 = bm.verts[v1_index]
        v2 = bm.verts[v2_index]

        nodes = bm_shortest_path(bm, v1, v2)
        node = nodes[v2]

        for e in node.shortest_path:
            e.select_set(True)
        bm.select_flush(True)

        verts = [v for v in bm.verts if v.select]
        selected_verts.extend(verts)
        i += 1
    vert_groups['Leg 2 Bottom'] = selected_verts
    bm_deselect_all(bm)

    # end wall
    inner_locs = vert_locs['End Wall Inner'][::-1]
    outer_locs = vert_locs['End Wall Outer']

    selected_verts = []
    i = 0
    while i < len(inner_locs) and i < len(outer_locs):
        v1_co, v1_index, dist = kd.find(inner_locs[i])
        v2_co, v2_index, dist = kd.find(outer_locs[i])

        bm.verts.ensure_lookup_table()
        v1 = bm.verts[v1_index]
        v2 = bm.verts[v2_index]

        nodes = bm_shortest_path(bm, v1, v2)
        node = nodes[v2]

        for e in node.shortest_path:
            e.select_set(True)
        bm.select_flush(True)

        verts = [v for v in bm.verts if v.select]
        selected_verts.extend(verts)
        i += 1
    vert_groups['End Wall Bottom'] = selected_verts
    bm_deselect_all(bm)

    # top
    vert_groups['Leg 1 Top'] = []
    vert_groups['Leg 2 Top'] = []
    vert_groups['End Wall Top'] = []

    bm.verts.ensure_lookup_table()
    for v in vert_groups['Leg 1 Bottom']:
        v_co, v_index, dist = kd.find((v.co[0], v.co[1], v.co[2] + height))
        vert_groups['Leg 1 Top'].append(bm.verts[v_index])

    bm.verts.ensure_lookup_table()
    for v in vert_groups['Leg 2 Bottom']:
        v_co, v_index, dist = kd.find((v.co[0], v.co[1], v.co[2] + height))
        vert_groups['Leg 2 Top'].append(bm.verts[v_index])

    bm.verts.ensure_lookup_table()
    for v in vert_groups['End Wall Bottom']:
        v_co, v_index, dist = kd.find((v.co[0], v.co[1], v.co[2] + height))
        vert_groups['End Wall Top'].append(bm.verts[v_index])

    return vert_groups
Esempio n. 15
0
 def test_kdtree_invalid_size(self):
     with self.assertRaises(ValueError):
         kdtree.KDTree(-1)
    def get_closest_vertex(self):

        if hasattr(self.bm.verts, "ensure_lookup_table"):
            self.bm.verts.ensure_lookup_table()

        kd = kdtree.KDTree(len(self.bm.verts))
        for i, v in enumerate(self.bm.verts):
            kd.insert(v.co, i)
        kd.balance()
        kd_closest_vertex = kd.find_n(self.hit_location, MAX_SEARCH)

        #print("kd_closest_vertex ", kd_closest_vertex)
        #print(">Av ", self.active_vertex)
        neighbors = []
        for c in kd_closest_vertex:
            v = self.bm.verts[c[1]]
            if (len(self.bm.verts) == 1 or v.is_wire or v.is_boundary or v in self.active_solution[1]) and (v != self.active_vertex):
                # 0 index, 1 distance, 2 hit distance, 3 score
                neighbors.append([v, c[2], 0., [1.]])

        #print("neighbors ", neighbors)

        # Sort
        n = float(len(neighbors))
        if(n > 1):
            max_hit_distance = -1.
            #min_hit_distance = float('inf')

            #max_distance = -1.
            #min_distance = float('inf')

            for i, v in enumerate(neighbors):

                c_hit_distance, c_hit_normal = get_closest_ray_hit_test(v[0], self.object, self.snap_obj, self.hit_normal)
                #print("c_hit_distance", c_hit_distance)
                if(c_hit_normal != None):
                    v[3].append( (n - i) / n)
                    v[2] = c_hit_distance + SNAP_TOLERANCE

                    hit_conform = 1
                    if(not v[0].is_wire):
                        conform_angle = v[0].normal.angle(c_hit_normal, pi)
                        hit_conform = (-(conform_angle / pi)**2 + 1) / 2 + 0.5
                    v[3].append(hit_conform)

                    conform = 1
                    if(not v[0].is_wire):
                        conform_angle = v[0].normal.angle(self.hit_normal, pi)
                        conform = (-(conform_angle / pi)**2 + 1) / 2 + 0.5
                    v[3].append(conform)

                    #if(v[1] > max_distance): max_distance = v[1]
                    #if(v[1] < min_distance): min_distance = v[1]

                    if(v[2] > max_hit_distance): max_hit_distance = v[2]
                    #if(v[2] < min_hit_distance): min_hit_distance = v[2]
                else:
                    v[3][0] = 0


            for v in neighbors:
                if ( (1. - v[2]/max_hit_distance) > 0.5):
                    v[3].append( 1.)
                else:
                    v[3].append(.5)

                #v[3].append(v[1] / max_distance)

            neighbors.sort(key=lambda x: prod(x[3]), reverse=True)

        if (neighbors != []):
            #for v in neighbors:
                #try:
                #    print("--- v %5d "% v[0].index, "| [dist %.3f, conform %.3f, snap dist %.3f]"% (v[3][1], v[3][2], v[3][3]))
                #except:
                #    pass
            return (neighbors[0][0], neighbors[0][1])
        else:
            return (None, None)
Esempio n. 17
0
    def add_geometry(self):
        
        DEBUG = False
        self.time_it = BL_TOOLS.TimeIt()
        BL_DEBUG.clear_marks()
        self.bm.verts.ensure_lookup_table()
        self.bm.edges.ensure_lookup_table()
        self.bm.faces.ensure_lookup_table()
        
        # create a kd tree with the vertex positions



        vertex = []
        for v in self.selected_vertex:
            if v.is_valid:
                vertex.append(v.index)
        
        # remove dupes
        vertex = list(set(vertex))

        kd = kdtree.KDTree(len(vertex))
        for v in vertex:
            ##BL_DEBUG.set_mark(self.bm.verts[v].co,kind="CUBE",scale=0.2)
            kd.insert(self.bm.verts[v].co, v)
        kd.balance()

        def nearest_points(kd, edge, v0, side, Nitems=7):
            nearest = []
            for (co, index, dist) in kd.find_n(v0, Nitems):
                # calculate normals
                A = self.obj_t.matrix_world @ edge[0].co
                B = self.obj_t.matrix_world @ edge[1].co
                C = self.obj_t.matrix_world @ co
                normal_vec = Vector(B-A).cross(Vector(C-A))
                normal_rl = normal_vec.z
                if normal_rl < 0.0 and side.upper() == 'RIGHT':
                    nearest.append( (co, index, dist) )
                if normal_rl > 0.0 and side.upper() == 'LEFT':
                    nearest.append( (co, index, dist) )
            return(nearest)

        # iterate my vertex, and find the nearest point my vertex

        side_keys = { 0: 'right', 1: 'left', 'right': 0, 'left': 1}
        
        count = 0
        B = C = None

        for plane in self.mesh_vertex:
            print(plane)
            nearest = {}
            # calculate the nearest point for each point, for each side
            for i in range(len(plane)):
                if i == 0:
                    #right ARROWS->CUBES
                    kind = 'ARROWS'
                else:
                    #left AXES->SPHERES
                    kind = 'PLAIN_AXES'
                #BL_DEBUG.set_mark(self.obj_t.matrix_world @ plane[i][0].co,kind=kind)
                #BL_DEBUG.set_mark(self.obj_t.matrix_world @ plane[i][1].co,kind=kind)

                nearest[side_keys[i]] = [   
                    nearest_points(kd, plane[i], self.obj_t.matrix_world @ plane[i][0].co, side_keys[i]),
                    nearest_points(kd, plane[i], self.obj_t.matrix_world @ plane[i][1].co, side_keys[i]) 
                ]

            A = plane[0][1]
            D = plane[0][0]

            # lower point
            if not C:   
                _,C,_ = nearest['right'][0][0]
                _,B,_ = nearest['right'][1][0]
                if B == C:
                    _,B,_ = nearest['right'][1][1]

            else:
                C = B
                _,B,_ = nearest['right'][1][0]
                if B == C:
                    _,B,_ = nearest['right'][1][1]

            print(A,B,C,D)
            # if not B in used_points.keys(): used_points[B] = 1
            # if not C in used_points.keys(): used_points[C] = 1

            # if B in used_points.keys() and used_points[B] < 2:
            #      used_points[B] += 1
            # else:
            #     B = None

            # if C in used_points.keys() and used_points[C] < 2:
            #     used_points[C] += 1
            # else:
            #     C = None
            
          

            # first point: nearest from top, and in nearest of bottom one.

            a = nearest['right'][0]
            print("r0-")
            for i in a:
                co,idx,dist = i
                print(co,idx,dist)
                DEBUG and BL_DEBUG.set_mark(co,kind="ARROWS")

            a = nearest['right'][1]
            print("r1-")            
            for i in a:
                co,idx,dist = i
                print(co,idx,dist)
                DEBUG and BL_DEBUG.set_mark(co,kind="ARROWS")

            a = nearest['left'][0]
            print("l0-")            
            for i in a:
                co,idx,dist = i
                print(co,idx,dist)
                DEBUG and BL_DEBUG.set_mark(co,kind="PLAIN_AXES")

            a = nearest['left'][1]
            print("l1-")
            for i in a:
                co,idx,dist = i
                print(co,idx,dist)
                DEBUG and BL_DEBUG.set_mark(co,kind="PLAIN_AXES")


            ## right side

            # top_vertex_list = []
            # for _,idx,_ in nearest['right'][1]:
            #     top_vertex_list.append(idx)

            # bottom_vertex_list = []
            # for _,idx,_ in nearest['right'][0]:
            #     bottom_vertex_list.append(idx)
            
            # # default, first item
            # # bottom
            
            # pB = None
            # get_next = False
            # _,pA,_ = nearest['right'][0][0]
            # for data in nearest['right'][0]:
            #     co,idx,dist = data
            #     if get_next:
            #         pA = idx
            #         break
            #     if idx in top_vertex_list and not pB:
            #         pB = pA
            #         get_next = True
  
            # if not pB:
            #     _,pB,_ = nearest['right'][1][0]
            #     for data in nearest['right'][1]:
            #         co,idx,dist = data
            #         pB = idx
            #         break

            if B and C:
                pBv = self.bm.verts[B]
                pCv = self.bm.verts[C]
                DEBUG and BL_DEBUG.set_mark(pBv.co,kind="CUBE")
                DEBUG and BL_DEBUG.set_mark(pCv.co,kind="CUBE")

                bmesh.ops.contextual_create(self.bm, geom=[A, pBv, pCv, D])
                self.bm.faces.index_update()            

            # ## left side
            # top_vertex_list = []
            # for i in nearest['left'][1]:
            #     co,idx,dist = i
            #     top_vertex_list.append(idx)

            # bottom_vertex_list = []
            # for i in nearest['left'][0]:
            #     co,idx,dist = i
            #     bottom_vertex_list.append(idx)

            # # default, first item
            # # bottom
            
            # pD = None
            # get_next = False
            # _,pC,_ = nearest['left'][0][0]
            # for data in nearest['left'][0]:
            #     co,idx,dist = data
            #     if get_next:
            #         pC = idx
            #         break
            #     if idx in top_vertex_list and not pD:
            #         pD = pC
            #         get_next = True
  
            # if not pD:
            #     _,pD,_ = nearest['left'][1][0]
            #     for data in nearest['left'][1]:
            #         co,idx,dist = data
            #         pD = idx
            #         break
        
            # pCv = self.bm.verts[pC]
            # pDv = self.bm.verts[pD]
            # DEBUG and BL_DEBUG.set_mark(pCv.co,kind="SPHERE")
            # DEBUG and BL_DEBUG.set_mark(pDv.co,kind="SPHERE")

            # if plane[0][1] != pBv and  pBv != pAv and pAv != plane[0][0]:
            #     bmesh.ops.contextual_create(self.bm, geom=[plane[0][0], pAv, pBv, plane[0][1]])
            #     self.bm.faces.index_update()
            # if plane[1][1] != pCv and  pCv != pDv and pDv != plane[1][0]:
            #     bmesh.ops.contextual_create(self.bm, geom=[plane[1][1], plane[1][0], pDv, pCv])
            #     self.bm.faces.index_update()
            

            # do just ones
            count +=1
            if count > 5:
                break



      # update the index of the new created verts. WTF ???
        self.update_bm()
        self.time_it.stop()
        print("[t] add_geometry(): ", self.time_it)
        #return(("ERROR", "Can't found terrain below the curve"))
        return(("INFO", "Done"))
Esempio n. 18
0
    def update(self):
        if 'vec' in self.inputs and 'edg' in self.inputs:
            print(self.name, 'is starting')
            if self.inputs['vec'].links and self.inputs['edg'].links:

                
                vec = self.inputs['vec'].sv_get()
                edg = self.inputs['edg'].sv_get()
                vecplan = self.inputs['vecplan'].sv_get()
                edgplan = self.inputs['edgplan'].sv_get()
                loc = self.inputs['loc'].sv_get()
                norm = self.inputs['norm'].sv_get()
                thick = self.inputs['thick'].sv_get()[0][0]
                sinuso60 = 0.8660254037844386
                sinuso60_minus = 0.133974596
                sinuso30 = 0.5
                sinuso45 = 0.7071067811865475
                if 'loccont' in self.inputs and self.inputs['loccont'].links and \
                       'normcont' in self.inputs and self.inputs['normcont'].links:
                    vecont = self.inputs['vecont'].sv_get()
                    loccont = self.inputs['loccont'].sv_get()
                    normcont = self.inputs['normcont'].sv_get()
                    vec_cont = Vector_generate(vecont)
                    loc_cont = Vector_generate(loccont)
                    norm_cont = Vector_generate(normcont)
                else:
                    norm_cont = [[Vector((0,0,1)) for i in range(len(norm[0]))]]
                    loc_cont = [[Vector((0,0,10000)) for i in range(len(norm[0]))]]
                    vec_cont = [[Vector((1000,0,1))] for i in range(len(norm[0]))]
                outeup = []
                outelo = []
                vupper = []
                vlower = []
                vec_ = Vector_generate(vec)
                loc_ = Vector_generate(loc)
                norm_ = Vector_generate(norm)
                vecplan_ = Vector_generate(vecplan)
                #print(self.name, 'veriables: \n', \
                #      vec_,'\n',
                #      vecplan_,'\n',
                #      loc_,'\n',
                #      loc_cont)
                for l,n,vecp, edgp in zip(loc_[0],norm_[0],vecplan_,edgplan):
                    newinds1 = edgp.copy()
                    newinds2 = edgp.copy()
                    vupperob = vecp.copy()
                    vlowerob = vecp.copy()
                    deledges1 = []
                    deledges2 = []
                    k = 0
                    lenvep = len(vecp)
                    # KDtree collections closest to join edges to sockets
                    tree = KDT.KDTree(lenvep)
                    for i,v in enumerate(vecp):
                        tree.insert(v,i)
                    tree.balance()
                    # to define bounds
                    x = [i[0] for i in vecp]
                    y = [i[1] for i in vecp]
                    m1x,m2x,m1y,m2y = max(x), min(x), max(y), min(y)
                    # vertical edges iterations
                    # every edge is object - two points, one edge
                    for v in vec_:
                        # sort vertices by Z value
                        # find two vertices - one lower, two upper
                        vlist = [v[0],v[1]]
                        vlist.sort(key=lambda x: x[2], reverse=False)
                        # flip if coplanar to enemy plane
                        # flip plane coplanar
                        fliped = self.get_coplanar(v[0], loc_cont,norm_cont, vec_cont)
                        if fliped:
                            two, one = vlist
                        else:
                            one, two = vlist
                        # coplanar to owner
                        cop = abs(D2P(one,l,n))
                        # defining bounds
                        inside = one[0]<m1x and one[0]>m2x and one[1]<m1y and one[1]>m2y
                        # if in bounds and coplanar do:
                        #print(self.name,l, cop, inside)
                        if cop < 0.001 and inside:
                            '''
                            huge calculations. if we can reduce...
                            '''
                            # find shift for thickness in sockets
                            angle = radians(degrees(atan(n.y/n.x))+90)
                            thick_2 = thick/2
                            direction = Vector((cos(angle),sin(angle),0))*thick_2
                            #matr = Euler((0,0,angle),'YZX').to_matrix().to_4x4()
                            #matr.translation = 
                            #direction = matr
                            # вектор, индекс, расстояние
                            # запоминаем порядок
                            # находим какие удалить рёбра
                            # делаем выборку левая-правая точка
                            nearv_1, near_1 = tree.find(one)[:2]
                            nearv_2, near_2 = tree.find(two)[:2]
                            # indexes of two nearest points
                            # удалить рёбра что мешают спать заодно
                            en_0, en_1, de1 = self.calc_indexes(edgp, near_1)
                            deledges1.extend(de1)
                            en_2, en_3, de2 = self.calc_indexes(edgp, near_2)
                            deledges2.extend(de2)
                            # old delete
                            # en_0,en_1 = [[t for t in i if t != near_1] for i in edgp if near_1 in i]
                            # en_2,en_3 = [[t for t in i if t != near_2] for i in edgp if near_2 in i]
                            # print(vecp, one, direction, en_0, en_1)
                            # left-right indexes and vectors
                            # с учётом интерполяций по высоте
                            left1, right1, l1, r1, lz1, rz1 = \
                                    self.calc_leftright(vecp, one, direction, en_0, en_1, thick_2)
                            left2, right2, l2, r2, lz2, rz2 = \
                                    self.calc_leftright(vecp, two, direction, en_2, en_3, thick_2)

                            # средняя точка и её смещение по толщине материала
                            three = (one-two)/2 + two
                            if self.rounded:
                                '''рёбра'''
                                if fliped:
                                    doflip = -1
                                else:
                                    doflip = 1
                                # пазы формируем независимо от верх низ

                                outeob1 = [[lenvep+k+8,lenvep+k],[lenvep+k+1,lenvep+k+2],
                                          [lenvep+k+2,lenvep+k+3],[lenvep+k+3,lenvep+k+4],
                                          [lenvep+k+4,lenvep+k+5],[lenvep+k+5,lenvep+k+6],
                                          [lenvep+k+6,lenvep+k+7],[lenvep+k+7,lenvep+k+8],
                                          [lenvep+k+9,lenvep+k+1]]

                                outeob2 = [[lenvep+k,lenvep+k+1],[lenvep+k+1,lenvep+k+2],
                                          [lenvep+k+2,lenvep+k+3],[lenvep+k+3,lenvep+k+4],
                                          [lenvep+k+4,lenvep+k+5],[lenvep+k+5,lenvep+k+6],
                                          [lenvep+k+6,lenvep+k+7],[lenvep+k+7,lenvep+k+8],
                                          [lenvep+k+8,lenvep+k+9]]
                                # наполнение списков lenvep = length(vecp)
                                newinds1.extend([[l1, lenvep+k], [lenvep+k+9, r1]])
                                newinds2.extend([[l2, lenvep+k+9], [lenvep+k, r2]])
                                '''Вектора'''
                                thick_3 = thick/3
                                thick_6 = thick/6
                                round1 = Vector((0,0,doflip*thick_3))
                                round2 = Vector((0,0,doflip*thick_3*sinuso30))
                                round2_= direction/3 + direction*(2*sinuso60/3)
                                round3 = Vector((0,0,doflip*thick_3*sinuso60_minus))
                                round3_= direction/3 + direction*(2*sinuso30/3)
                                round4 = direction/3
                                vupperob.extend([two-direction-Vector((0,0,lz2)),
                                                 three+round1-direction, three+round2-round2_,
                                                 three+round3-round3_, three-round4,
                                                 three+round4, three+round3+round3_,
                                                 three+round2+round2_, three+round1+direction,
                                                 two+direction-Vector((0,0,rz2))])
                                vlowerob.extend([one+direction-Vector((0,0,rz1)),
                                                 three-round1-direction, three-round2-round2_,
                                                 three-round3-round3_, three-round4,
                                                 three+round4, three-round3+round3_,
                                                 three-round2+round2_, three-round1+direction,
                                                 one-direction-Vector((0,0,lz1))])
                                k += 10
                            else:
                                '''рёбра'''
                                # пазы формируем независимо от верх низ
                                outeob1 = [[lenvep+k,lenvep+k+1],[lenvep+k+1,lenvep+k+2],[lenvep+k+2,lenvep+k+3]]
                                outeob2 = [[lenvep+k,lenvep+k+1],[lenvep+k+1,lenvep+k+2],[lenvep+k+2,lenvep+k+3]]
                                # наполнение списков lenvep = length(vecp)
                                newinds1.extend([[l1, lenvep+k], [lenvep+k+3, r1]])
                                newinds2.extend([[l2, lenvep+k+3], [lenvep+k, r2]])
                                '''Вектора'''
                                vupperob.extend([two-direction-Vector((0,0,lz2)), three-direction, 
                                                 three+direction, two+direction-Vector((0,0,rz2))])
                                vlowerob.extend([one+direction-Vector((0,0,rz1)), three+direction,
                                                 three-direction, one-direction-Vector((0,0,lz1))])
                                k += 4
                            newinds1.extend(outeob1)
                            newinds2.extend(outeob2)
                    del tree
                    for e in deledges1:
                        if e in newinds1:
                            newinds1.remove(e)
                    for e in deledges2:
                        if e in newinds2:
                            newinds2.remove(e)
                    if vupperob or vlowerob:
                        outeup.append(newinds2)
                        outelo.append(newinds1)
                        vupper.append(vupperob)
                        vlower.append(vlowerob)
                vupper = Vector_degenerate(vupper)
                vlower = Vector_degenerate(vlower)
                
                if 'vupper' in self.outputs and self.outputs['vupper'].links:
                    out = dataCorrect(vupper)
                    SvSetSocketAnyType(self, 'vupper', out)
                if 'outeup' in self.outputs and self.outputs['outeup'].links:
                    SvSetSocketAnyType(self, 'outeup', outeup)
                if 'vlower' in self.outputs and self.outputs['vlower'].links:
                    SvSetSocketAnyType(self, 'vlower', vlower)
                if 'outelo' in self.outputs and self.outputs['outelo'].links:
                    SvSetSocketAnyType(self, 'outelo', outelo)
                print(self.name, 'is finishing')
    def __init__(self, context, cut_object, ui_type='DENSE_POLY'):
        self.cut_ob = cut_object
        self.bme = bmesh.new()
        self.bme.from_mesh(cut_object.data)
        self.bme.verts.ensure_lookup_table()
        self.bme.edges.ensure_lookup_table()
        self.bme.faces.ensure_lookup_table()

        non_tris = [f for f in self.bme.faces if len(f.verts) > 3]
        #if len(non_tris):
        #geom = bmesh.ops.connect_verts_concave(self.bme, non_tris)
        #self.bme.verts.ensure_lookup_table()
        #self.bme.edges.ensure_lookup_table()
        #self.bme.faces.ensure_lookup_table()

        self.bvh = BVHTree.FromBMesh(self.bme)

        self.cyclic = False
        self.start_edge = None
        self.end_edge = None

        self.pts = []
        self.cut_pts = []  #local points
        self.normals = []

        self.face_map = []  #all the faces that user drawn poly line fall upon
        self.face_changes = [
        ]  #the indices where the next point lies on a different face
        self.face_groups = dict(
        )  #maps bmesh face index to all the points in user drawn polyline which fall upon it
        self.new_ed_face_map = dict(
        )  #maps face index in bmesh to new edges created by bisecting

        self.ed_map = []  #existing edges in bmesh crossed by cut line
        self.new_cos = []  #location of crosses

        self.non_man_eds = [
            ed.index for ed in self.bme.edges if not ed.is_manifold
        ]
        self.non_man_ed_loops = edge_loops_from_bmedges(
            self.bme, self.non_man_eds)

        #print(self.non_man_ed_loops)
        self.non_man_points = []
        self.non_man_bmverts = []
        for loop in self.non_man_ed_loops:
            self.non_man_points += [
                self.cut_ob.matrix_world * self.bme.verts[ind].co
                for ind in loop
            ]
            self.non_man_bmverts += [self.bme.verts[ind].index for ind in loop]
        if len(self.non_man_points):
            kd = kdtree.KDTree(len(self.non_man_points))
            for i, v in enumerate(self.non_man_points):
                kd.insert(v, i)

            kd.balance()
            self.kd = kd
        else:
            self.kd = None

        self.face_chain = set()  #all faces crossed by the cut curve
        if ui_type not in {'SPARSE_POLY', 'DENSE_POLY', 'BEZIER'}:
            self.ui_type = 'SPARSE_POLY'
        else:
            self.ui_type = ui_type

        self.selected = -1
        self.hovered = [None, -1]

        self.grab_undo_loc = None
        self.start_edge_undo = None
        self.end_edge_undo = None

        self.mouse = (None, None)

        #keep up with these to show user
        self.bad_segments = []
        self.split = False
        self.face_seed = None
Esempio n. 20
0
    def add_geometry_edge(self):

        "try to match near edges"

        def edge_median(edge):
                v0,v1 = edge.verts
                median = v0.co + ((v0.co-v1.co)/2.0)
                return(median)

        def nearest_points(kd, edge, v0, side, Nitems=7):
            nearest = []
            for (co, index, dist) in kd.find_n(v0, Nitems):
                # calculate normals
                A = self.obj_t.matrix_world @ edge[0].co
                B = self.obj_t.matrix_world @ edge[1].co
                C = self.obj_t.matrix_world @ co
                normal_vec = Vector(B-A).cross(Vector(C-A))
                normal_rl = normal_vec.z
                if normal_rl < 0.0 and side.upper() == 'RIGHT':
                    nearest.append( (co, index, dist) )
                if normal_rl > 0.0 and side.upper() == 'LEFT':
                    nearest.append( (co, index, dist) )
            return(nearest)

        def nearest_edge(kd, edge, side, Nitems=7):
            
            nearest = []
            median = edge_median(edge)

            for (co, index, dist) in kd.find_n(self.obj_t.matrix_world @ median, Nitems):
                # calculate normals
                A = self.obj_t.matrix_world @ edge.verts[0].co
                B = self.obj_t.matrix_world @ edge.verts[1].co
                C = self.obj_t.matrix_world @ co
                normal_vec = Vector(B-A).cross(Vector(C-A))
                normal_rl = normal_vec.z
                if normal_rl < 0.0 and side.upper() == 'RIGHT':
                    nearest.append( (co, index, dist) )
                if normal_rl > 0.0 and side.upper() == 'LEFT':
                    nearest.append( (co, index, dist) )
            return(nearest)

        DEBUG = False
        self.time_it = BL_TOOLS.TimeIt()
        BL_DEBUG.clear_marks()
        self.bm.verts.ensure_lookup_table()
        self.bm.edges.ensure_lookup_table()
        self.bm.faces.ensure_lookup_table()
        
        # create a kd tree with the median edge positions.

        median_edges = []
        for edge in self.inner_edges:
            if edge.is_valid and edge.is_boundary:
                median = edge_median(edge)
                median_edges.append( (median, edge.index) )
        
        kd = kdtree.KDTree(len(median_edges))
        for median,idx in median_edges:
            kd.insert(median, idx)
        kd.balance()

        # iterate my vertex, and find the nearest point my vertex

        side_keys = { 0: 'right', 1: 'left', 'right': 0, 'left': 1}
        
        count = 0
        for plane in self.mesh_vertex:
            print("plane", plane)
            nearest = {}
            # calculate the nearest point for each point, for each side
            for i in range(len(plane)):
                if i == 0:
                    #right ARROWS->CUBES
                    kind = 'ARROWS'
                else:
                    #left AXES->SPHERES
                    kind = 'PLAIN_AXES'
          

                #nearest[side_keys[i]] = [   
                #    nearest_points(kd, plane[i], self.obj_t.matrix_world @ plane[i][0].co, side_keys[i]),
                #    nearest_points(kd, plane[i], self.obj_t.matrix_world @ plane[i][1].co, side_keys[i]) 
                #]
                
                # create the working edge
                edge = [ plane[i][0], plane[i][1] ] 
                

                ret_geom = bmesh.ops.contextual_create(self.bm, geom= edge)
                self.bm.edges.index_update()
                self.update_bm()
                for f in ret_geom['edges']:
                    if isinstance(f, bmesh.types.BMEdge):
                        edge = f

                median = edge_median(edge)
                BL_DEBUG.set_mark(self.obj_t.matrix_world @ median,kind='CUBE') ## mesh edge

                n_edge = nearest_edge(kd, edge, side_keys[i])

                
              
                # build the face, rebuild the tree
                co,idx,_ = n_edge[0]
                self.bm.verts.ensure_lookup_table()
                self.bm.edges.ensure_lookup_table()
                self.bm.faces.ensure_lookup_table()

                BL_DEBUG.set_mark(self.obj_t.matrix_world @ co,kind='SPHERE') ## found edge



                #ret_geom = bmesh.ops.contextual_create(self.bm, geom= [edge, self.bm.edges[idx]])
                self.bm.edges.index_update()
                self.update_bm()
                # remove the edge from the table.

                edges_tmp = []
                for edge in self.inner_edges:
                    if edge.is_valid and edge.index != idx:
                        edges_tmp.append(edge)

                self.inner_edges = edges_tmp
                median_edges = []
                for edge in self.inner_edges:
                    if edge.is_valid and edge.is_boundary:
                        median = edge_median(edge)
                        median_edges.append( (median, edge.index) )
                
                kd = kdtree.KDTree(len(median_edges))
                for median,idx in median_edges:
                    kd.insert(median, idx)
                kd.balance()                
        
            # do just ones
            count +=1
            if count >=1:
                break



      # update the index of the new created verts. WTF ???
        self.update_bm()
        self.time_it.stop()
        print("[t] add_geometry_edges(): ", self.time_it)
        #return(("ERROR", "Can't found terrain below the curve"))
        return(("INFO", "Done"))
Esempio n. 21
0
    def do_holes(self):
        "get the plane, generate the info to raycast in the grid, select the matching faces"
        
        self.time_it = BL_TOOLS.TimeIt()

        EXTEND_SELECTION = True
        TRIANGULATE_FACES = False # True
        SUBDIVIDE_INNER_FACES = False
        EXTEND_DELETE_SELECTION = False
        SUBDIVIDE_INNER_EDGES = True
        CALCULATE_NEAR_FACES = True
        MIN_FACE_DIST = 3

        BL_DEBUG.clear_marks()

        # at this point XD point_data has 
        # terrain_up/down, face_index, point, location)
              
        self.unselect_all()

        self.selected_faces = []
        # select faces tracked
        for point in self.raycast_points:
            terrain_down, index, point, location = point
            self.bm.faces[index].select = True
            if self.bm.faces[index] not in self.selected_faces:
                self.selected_faces.append(self.bm.faces[index])
        
        if EXTEND_SELECTION:
            ret_geom =  bmesh.ops.region_extend(self.bm, 
                geom=self.selected_faces,
                use_faces=True, 
                use_face_step=False,
                use_contract=False)
            
            for f in ret_geom['geom']:
                if isinstance(f, bmesh.types.BMFace):
                    f.select = True
                    self.selected_faces.append(f)

        if SUBDIVIDE_INNER_FACES:
            # subdivide the inner faces
            #el_faces = [f for f in self.bm.faces if f.select]
            face_edges = []
            for f in self.selected_faces:
                for e in f.edges:
                    face_edges.append(e.index)
            face_edges = list(set(face_edges))
            face_edges_geom = [self.bm.edges[i] for i in face_edges]
            ret = bmesh.ops.subdivide_edges(self.bm, edges=face_edges_geom, cuts=2, use_grid_fill=True)
            for f in ret['geom']:
                if isinstance(f, bmesh.types.BMFace):
                    f.select = True
                    self.selected_faces.append(f)


        if TRIANGULATE_FACES:
            #triangulate
            geom = [f for f in self.bm.faces if f.select]
            ret_trig = bmesh.ops.triangulate(self.bm, faces=geom)        
            # select the new created triangles

            for f in ret_trig['faces']:
                    f.select = True
                    self.selected_faces.append(f)
               

        # 0. at this point, faces are triangulated, and selected
 
        ##############################################################
        #
        # 1. delete the faces recalculate again the faces
        # this version only deletes the nearest faces from the 
        # road. Maybe it's a little narrow
        # 
        ##############################################################
   
        self.update_bm()

        #self.bm.verts.ensure_lookup_table()
        #self.bm.edges.ensure_lookup_table()
        self.bm.faces.ensure_lookup_table()
        
        #        
        # I have to CHANGE to OBJECT in order to keep working on that
        # and update the structure. After change, return to edit and
        # keep working, it works.
        # 
              
                

        # after triangulate, or adding more faces, there's a need of recalculate again the affected
        # faces to make the hole

        self.raycast_points =  BL_TOOLS.get_raycast(self.plane, self.terrain, 
                                    vertices = self.plane_points,
                                    DEBUG=self.DEBUG, LIMIT=self.LIMIT)
        
        # at this point XD point_data has 
        # terrain_up/down, face_index, point, location)
        
        BL_DEBUG.clear_marks()

        faces_to_delete = {}

        for item in self.raycast_points:
            terrain_down, index, point, location = item
            #print(terrain_down,index, point, location)
            #BL_DEBUG.set_mark( obj_t.matrix_world @ location.xyz, kind="PLAIN_AXES" )

            if index not in faces_to_delete.keys():
                faces_to_delete[index] = self.bm.faces[index]

        if EXTEND_DELETE_SELECTION:

            for face in self.bm.faces: face.select = False
 
            for f in faces_to_delete.keys():
                self.bm.faces[f].select = True        

            #sel_verts = [v for v in self.bm.verts if v.select]
            #sel_edges = [e for e in self.bm.edges if e.select]
            selected_faces_local = [f for f in self.bm.faces if f.select]
            geom = selected_faces_local

            ret_geom =  bmesh.ops.region_extend(self.bm, 
                        geom=selected_faces_local,
                        use_faces=True, 
                        use_face_step=False,
                        use_contract=False)

            for f in ret_geom['geom']:
                if isinstance(f, bmesh.types.BMFace):
                    faces_to_delete[f.index] = self.bm.faces[f.index]


        # delete the result faces        

        faces_to_delete = list(faces_to_delete.values())
        deleted_geom_edges = []
        for f in faces_to_delete:
            deleted_geom_edges += [e for e in f.edges]

        bmesh.ops.delete(self.bm, geom=faces_to_delete, context='FACES_KEEP_BOUNDARY') # FACES_ONLY

        # remove deleted faces from the selected container
        #temp_faces = [f for f in self.selected_faces if f.is_valid]
        #self.selected_faces = temp_faces
        

        # this creates a subdivision of the inner vertex.
        if SUBDIVIDE_INNER_EDGES:
            # subdivide existing edges
            keep_edges = []
            for edge in deleted_geom_edges:
                if edge.is_valid:
                    keep_edges.append(edge)

            self.inner_edges = []
            print("Inner edges: %d" % (len(keep_edges)*2))

            geom_created = bmesh.ops.subdivide_edges(self.bm, edges=keep_edges, cuts=1, use_grid_fill=True)
            for item in geom_created['geom_split']:
                if isinstance(item, bmesh.types.BMVert):
                    pass
                    #item.select = True
                    #print(item.index)
                    #self.inner_edges.append(item)                
                if isinstance(item, bmesh.types.BMEdge):
                    #item.select = True
                    #print(item.index)
                    self.inner_edges.append(item)
                if isinstance(item, bmesh.types.BMFace):
                    #item.select = True
                    print(item.index)
                    item.select = True
                    self.selected_faces.append(item)
           

            print("Inner edges Subdivide: %d" % (len(self.inner_edges)*2) )

        self.update_bm()

        # create a KD tree for faces. add the center, and get only faces that are "near" in radious

        if CALCULATE_NEAR_FACES:

            valid_faces = [face for face in self.selected_faces if face.is_valid]
            kd = kdtree.KDTree(len(valid_faces))
            for face in valid_faces:
                kd.insert(face.calc_center_median(), face.index)
            kd.balance()

            faces_to_delete = {}
            verts_to_delete = {}
            edges_to_delete = {}
            self.bm.faces.ensure_lookup_table()
            self.bm.verts.ensure_lookup_table()
            self.bm.edges.ensure_lookup_table()

            for item in self.raycast_points:
                terrain_down, index, point, location = item
                
                local_faces = []
                local_point = self.plane_to_terrain_point(point.co)
           
                for (co, index, dist) in kd.find_range(local_point, 200):
                    #print("face_local", index)
                    local_faces.append(self.bm.faces[index])

                for f in local_faces:
                    # check for deleted faces!
                    if f.is_valid and f.index not in faces_to_delete.keys():
                        #center = BL_FLATTEN.DummyVector(f.calc_center_median())
                        for fv in f.verts:
                        #for fv in [center]:
                            vpw = self.obj_s.matrix_world @ point.co
                            vtw = self.obj_t.matrix_world @ fv.co
                            dist = (vpw.xy - vtw.xy).length
                            if dist < MIN_FACE_DIST:
                                #print("Face too near: ",f.index,dist)
                                faces_to_delete[f.index] = self.bm.faces[f.index]        
                                for e in f.edges:
                                    edges_to_delete[e.index] = self.bm.edges[e.index]
                                for v in f.verts:
                                    verts_to_delete[v.index] = self.bm.verts[v.index]

            faces_to_delete = list(faces_to_delete.values())
            verts_to_delete = list(verts_to_delete.values())
            edges_to_delete = list(edges_to_delete.values())
            # FACES_ONLY
            bmesh.ops.delete(self.bm, geom=verts_to_delete + edges_to_delete + faces_to_delete, context='FACES') 

        self.update_bm()

        # now, just select the faces that are not select, but are in the edges.
        # also select all the vertex in the keep edges that are not selected by default.

        for e in self.inner_edges:
            if not e.is_valid:
                continue
            for v in e.verts: 
                if not v.is_valid: 
                    continue
                v.select = True
                for f in v.link_faces:
                    f.select = True
                    if f not in self.selected_faces:
                        self.selected_faces.append(f)

        # select vertex that are in a boundary (internal)
        self.selected_vertex = []
        for e in self.bm.edges:
            if e.is_valid and e.is_boundary:
                for v in e.verts:
                    self.selected_vertex.append(v)

        ##############################################################
        #
        # End
        # update the meshes
        # 
        ##############################################################  

        self.time_it.stop()
        self.update_bm()

        print("[t] do_holes(): ", self.time_it)

        
        #return(("ERROR", "Can't found terrain below the curve"))
        return(("INFO", "Done"))        
Esempio n. 22
0
    def align_curve_tilt(context,
                         Curve,
                         align_target_bvht,
                         resetTilt=False,
                         onlySelection=False):
        if Curve.mode == 'EDIT':  # to make transfrom() work in edit mode
            bpy.ops.object.mode_set(mode="OBJECT")
            Curve.data.transform(Curve.matrix_world)
            bpy.ops.object.mode_set(mode="EDIT")
        else:
            Curve.data.transform(Curve.matrix_world)
        if resetTilt:
            HT_OT_CurvesTiltAlign.resetTiltFunction(Curve.data, onlySelection)
        curveBevelObj = Curve.data.bevel_object  # backup
        context.active_object.data.bevel_object = None  # zero out to prevent changing default one
        curveResU = Curve.data.resolution_u  # backup
        context.depsgraph.scene.update()
        if 'Align_curve_helper' in bpy.data.objects.keys():
            Curve.data.bevel_object = bpy.data.objects['Align_curve_helper']
        else:
            bpy.ops.object.generate_ribbons(
                strandResV=2,
                strandResU=curveResU,
                strandWidth=0.01,
                strandPeak=0,
                skipInitProps=True)  # for temp curve for tangent and normals
            Curve.data.bevel_object.name = 'Align_curve_helper'

        meFromCurve = Curve.to_mesh(context.depsgraph,
                                    True,
                                    calc_undeformed=False)
        meshVertCount = len(meFromCurve.vertices)
        kdMeshFromCurve = kdtree.KDTree(meshVertCount)
        for i, v in enumerate(meFromCurve.vertices):
            kdMeshFromCurve.insert(v.co, i)
        kdMeshFromCurve.balance()
        curveData = Curve.data

        unitsScale = context.scene.unit_settings.scale_length
        searchDistance = 10 / unitsScale
        angleFlipFix = [-2 * math.pi, -math.pi, 2 * math.pi, math.pi]
        for i, polyline in enumerate(curveData.splines):  # for strand point
            pointsNumber = len(
                polyline.bezier_points) if polyline.type == 'BEZIER' else len(
                    polyline.points)
            if polyline.type == 'NURBS' or polyline.type == 'POLY':
                if onlySelection:
                    spline_selection_mask = np.zeros(pointsNumber,
                                                     dtype=np.bool)
                    polyline.points.foreach_get('select',
                                                spline_selection_mask)
                    if not any(spline_selection_mask):
                        continue  # if not even one pointis selected
                points = polyline.points
            else:
                if onlySelection:
                    spline_selection_mask = np.zeros(pointsNumber,
                                                     dtype=np.bool)
                    polyline.bezier_points.foreach_get('select_control_point',
                                                       spline_selection_mask)
                    if not any(spline_selection_mask):
                        continue  # if not even one point is selected
                points = polyline.bezier_points
            # helper for tangetnt function (to detect last point on cuve)
            prevAngle = 0
            corrective_angles = np.zeros(pointsNumber, dtype=np.float16)
            current_tilt = np.zeros(pointsNumber, dtype=np.float16)
            points.foreach_get('tilt', current_tilt)

            for j, curvePoint in enumerate(points):  # for strand point
                pointOnMeshLoc, normSnapTarget, face_index, distance, isInside = \
                    HT_OT_CurvesTiltAlign.find_nearest(curvePoint.co.xyz, align_target_bvht, searchDistance)

                # get vertex closest to spline point (for normal) from temp spline representation
                co, index, dist = kdMeshFromCurve.find(curvePoint.co.xyz)
                curveNormal = meFromCurve.vertices[index].normal

                vecSurfaceHit = curvePoint.co.xyz - pointOnMeshLoc
                if isInside:  # if curve point is outside snapSurface flip it
                    vecSurfaceHit *= -1

                # vecSurfaceHit = normSnapTarget * -1  # less accurate but faster...
                if index + 3 < meshVertCount:  # for last spline just use prvevangle
                    tangent = HT_OT_CurvesTiltAlign.get_tangents(
                        meFromCurve, index, j == pointsNumber -
                        1)  # for bezier we can gets handles for tanget
                    biTangentCurve = tangent.cross(curveNormal)
                    vectSurfHitProjected90 = tangent.cross(vecSurfaceHit)
                    vectSurfHitProjectedToTangent = vectSurfHitProjected90.cross(
                        tangent)
                    # angle = biTangentCurve.angle(vectSurfHitProjectedToTangent)  #unsigned angle 0 - 180
                    angle = angle_signed(
                        biTangentCurve, vectSurfHitProjectedToTangent,
                        tangent) - math.pi / 2  # a,b, vN  - signed -180 to 180
                    if j > 1 and abs(
                            prevAngle - angle
                    ) > math.pi / 2:  # try fixing random flips in ribbons surface
                        fix = [
                            fix_angle for fix_angle in angleFlipFix
                            if abs(prevAngle - fix_angle - angle) < math.pi / 2
                        ]
                        if len(fix) > 0:
                            angle += fix[0]
                    corrective_angles[j] = angle
                    prevAngle = angle
                else:
                    corrective_angles[j] = prevAngle
            # current_tilt = current_tilt + corrective_angles
            if pointsNumber >= 4:
                corrective_angles[1] = (corrective_angles[2] +
                                        corrective_angles[3]) / 2
                corrective_angles[0] = (corrective_angles[1] +
                                        corrective_angles[2]) / 2
            elif pointsNumber == 3:
                corrective_angles[0] = (corrective_angles[1] +
                                        corrective_angles[2]) / 2
            if onlySelection:
                current_tilt[spline_selection_mask] += corrective_angles[
                    spline_selection_mask]
            else:
                current_tilt += corrective_angles
            points.foreach_set('tilt', current_tilt.ravel())  # in radians
            # manually smooth first two points cos they are usually broken

        bpy.data.meshes.remove(meFromCurve)

        Curve.data.bevel_object = curveBevelObj  # restore old bevel obj
        was_edit = False
        if Curve.mode == 'EDIT':  # to make transfrom() work in edit mode
            was_edit = True
            bpy.ops.object.mode_set(mode="OBJECT")
        Curve.data.transform(Curve.matrix_world.inverted())

        if Curve.rotation_euler != Euler((0.0, 0.0, 0.0), 'XYZ') or min(
                Curve.scale[:]
        ) < 0:  # fix rot if curve rot is non 0,0,0, or scele x,y,z <0
            override = {'selected_editable_objects': [Curve]}
            if Curve.data.users > 1:
                Curve.data = Curve.data.copy()
            bpy.ops.object.transform_apply(override,
                                           location=False,
                                           rotation=True,
                                           scale=True)

        if was_edit:
            bpy.ops.object.mode_set(mode="EDIT")
Esempio n. 23
0
 def __init__(self, points):
     self.kdtree = kdtree.KDTree(len(points))
     for i, v in enumerate(points):
         self.kdtree.insert(v, i)
     self.kdtree.balance()
    def get_closest_vertex(self):

        if hasattr(self.bm.verts, "ensure_lookup_table"):
            self.bm.verts.ensure_lookup_table()

        kd = kdtree.KDTree(len(self.bm.verts))
        for i, v in enumerate(self.bm.verts):
            kd.insert(v.co, i)
        kd.balance()
        kd_closest_vertex = kd.find_n(self.hit_location, MAX_SEARCH)

        #print("kd_closest_vertex ", [v[1] for v in kd_closest_vertex])
        #if(self.closest_vertex != None): print("Closest: ", self.closest_vertex.index)
        neighbors = []
        for c in kd_closest_vertex:
            v = self.bm.verts[c[1]]
            if (len(self.bm.verts) == 1 or v.is_wire or v.is_boundary or v
                    in self.active_solution[1]) and (v != self.active_vertex):
                # 0 index, 1 distance, 2 hit distance, 3 score
                neighbors.append([v, c[2], 0., []])

        #print("neighbors ", neighbors)

        # Sort
        n = float(len(neighbors))
        if (n > 1):
            max_hit_distance = -1.

            for i, v in enumerate(neighbors):

                c_hit_distance, c_hit_normal = get_closest_ray_hit_test(
                    v[0], self.object, self.snap_obj, self.hit_normal)

                #print("c_hit_distance", c_hit_distance)

                if (c_hit_normal != None):
                    v[3].append((n - i) / n)
                    v[2] = c_hit_distance + SNAP_TOLERANCE

                    hit_conform = 1
                    conform_angle = v[0].normal.angle(c_hit_normal, pi)
                    hit_conform = (-(conform_angle / pi)**2 + 1) / 2 + 0.5
                    v[3].append(hit_conform)

                    conform = 1
                    conform_angle = v[0].normal.angle(self.hit_normal, pi)
                    conform = (-(conform_angle / pi)**2 + 1) / 2 + 0.5
                    v[3].append(conform)

                    if (v[0].is_wire):
                        v[3].append(0.8)

                    if (v[2] > max_hit_distance): max_hit_distance = v[2]
                else:
                    v[3].append(0.)

            for v in neighbors:
                if ((1. - v[2] / max_hit_distance) > 0.5):
                    v[3].append(1.)
                else:
                    v[3].append(.5)

            ##### Closest on surface # 0 index, 1 distance, 2 hit distance, 3 score
            plane_distances = [
                abs((v[0].co - self.hit_location).dot(self.hit_normal))
                for v in neighbors
            ]
            max_distance_to_plane = max(plane_distances)

            for v, d in zip(neighbors, plane_distances):
                v[3].append(cos(d * pi / 2 / max_distance_to_plane) / 2 + 0.5)

            #####

            neighbors.sort(key=lambda x: prod(x[3]), reverse=True)

        if (neighbors != []):
            #for v in neighbors:
            #try:
            #print("--- v %5d "% v[0].index, "| [dist %.3f, conform %.3f, conform self %.3f, proj %.3f]"% (v[3][0], v[3][1], v[3][2], v[3][4]), " | ", str(v[3]))
            #except:
            #    pass
            return (neighbors[0][0], neighbors[0][1])
        else:
            return (None, None)
Esempio n. 25
0
    def transfer(self, target, operator = None, transfer_type='Shape'):
        context = bpy.context
        
        s = self.get_shape_settings(target)
        obj = self.id_data.dp_helper
        ob = self.id_data
        me = ob.data
        source = context.selected_objects[:]
        source.remove(ob)
        
        if operator:
            transfer_type = operator.transfer_type
        #with obj.bm(1) as bm:
        if transfer_type == 'Shape':
            if not me.shape_keys:
                ob.shape_key_add("Basis")
            kb = me.shape_keys.key_blocks
            for sk in s.transferable:
                key = kb.get(sk.name)
                if not key:
                    key = ob.shape_key_add(sk.name)
            me.update()
        source_ob = source[0].dp_helper
        #print(operator,transfer_type)
        
        with obj.bm(1) as bm:
            indices_id = bm.verts.layers.int.get("indices_save")
            if transfer_type == 'ID' and not indices_id:
                indices_id = bm.verts.layers.int.new('indices_save')
            
            with source_ob.bm() as sbm:
                source_verts = sbm.verts
                indices_id2 = sbm.verts.layers.int.get("indices_save")
                if not indices_id2 or not indices_id :
                    operator.report({"ERROR"},"Store indices first in source AND target")
                    return
                
                if transfer_type == 'ID':
                    from mathutils import kdtree
                    size = len(source_verts)
                    kd = kdtree.KDTree(size)
                    for i,v in enumerate(source_verts):
                        kd.insert(v.co, i)
                    kd.balance()
                    for i,v in enumerate(bm.verts):
                        if not v.select:continue
                        closest = kd.find_n(v.co,2)
                        #print(closest)
                        v[indices_id] = source_verts[closest[1][1]][indices_id2]
                        

                elif transfer_type == 'Shape':
                    mapped_source = { v[indices_id2]:v for v in source_verts } 
                    
                    for k in s.transferable:
                        source_shape_lay = sbm.verts.layers.shape.get(k.name)
                        target_lay = bm.verts.layers.shape.get(k.name)
                        #source_v = {
                        for v in bm.verts:
                            if mapped_source.get(v[indices_id]):
                                v[target_lay] = mapped_source[v[indices_id]][source_shape_lay]

        me.update()
Esempio n. 26
0
    def process(self):

        if 'vecLine' in self.inputs and \
                'vecPlane' in self.inputs and \
                'edgPlane' in self.inputs:
            print(self.name, 'is starting')
            if self.inputs['vecLine'].links and \
                    self.inputs['vecPlane'].links and \
                    self.inputs['edgPlane'].links:
                if self.bindCircle:
                    circle = [ (Vector((sin(radians(i)),cos(radians(i)),0))*self.circle_rad)/4 \
                              for i in range(0,360,30) ]
                vec = self.inputs['vecLine'].sv_get()
                vecplan = self.inputs['vecPlane'].sv_get()
                edgplan = self.inputs['edgPlane'].sv_get()
                if len(edgplan[0][0]) > 2:
                    edgplan = pols_edges(edgplan)
                thick = self.inputs['thick'].sv_get()[0][0]
                threshold_coplanar = 0.005
                sinuso60 = 0.8660254037844386
                sinuso60_minus = 0.133974596
                sinuso30 = 0.5
                sinuso45 = 0.7071067811865475
                thick_2 = thick / 2
                thick_3 = thick / 3
                thick_6 = thick / 6
                threshold = self.threshold
                if 'vecContr' in self.inputs and self.inputs['vecContr'].links:
                    vecont = self.inputs['vecContr'].sv_get()
                    #edgcont = self.inputs['edgContr'].sv_get()
                    vec_cont = Vector_generate(vecont)
                    loc_cont = [[i[0]] for i in vec_cont]
                    norm_cont = [[NM(i[0], i[len(i) // 2], i[-1])]
                                 for i in vec_cont]  # довести до ума
                else:
                    vec_cont = []
                if 'vecTube' in self.inputs and self.inputs['vecTube'].links:
                    vectube = self.inputs['vecTube'].sv_get()
                    vec_tube = Vector_generate(vectube)
                    tube_radius = self.inputs['radTube'].sv_get()[0][0]
                    circle_tube = [ (Vector((sin(radians(i)),cos(radians(i)),0))*tube_radius) \
                              for i in range(0,360,15) ]
                else:
                    vec_tube = []
                outeup = []
                outelo = []
                vupper = []
                vlower = []
                centers = []
                vec_ = Vector_generate(vec)
                vecplan_ = Vector_generate(vecplan)
                for centersver, vecp, edgp in zip(vecplan, vecplan_, edgplan):
                    tubes_flag_bed_solution_i_know = False
                    newinds1 = [list(e) for e in edgp]
                    newinds2 = newinds1.copy()
                    vupperob = vecp.copy()
                    vlowerob = vecp.copy()
                    deledges1 = []
                    deledges2 = []
                    # to define bounds
                    x = [i[0] for i in vecp]
                    y = [i[1] for i in vecp]
                    z = [i[2] for i in vecp]
                    m1x, m2x, m1y, m2y, m1z, m2z = max(x), min(x), max(y), min(
                        y), max(z), min(z)
                    l = Vector(
                        (sum(x) / len(x), sum(y) / len(y), sum(z) / len(z)))
                    n_select = [vecp[0], vecp[len(vecp) // 2],
                                vecp[-1]]  # довести до ума
                    n_select.sort(key=lambda x: sum(x[:]), reverse=False)
                    n_ = NM(n_select[0], n_select[1], n_select[2])
                    n_.normalize()
                    # а виновта ли нормаль?
                    if n_[0] < 0:
                        n = n_ * -1
                    else:
                        n = n_
                    cen = [sum(i) for i in zip(*centersver)]
                    centers.append(Vector(cen) / len(centersver))
                    k = 0
                    lenvep = len(vecp)
                    # KDtree collections closest to join edges to sockets
                    tree = KDT.KDTree(lenvep)
                    for i, v in enumerate(vecp):
                        tree.insert(v, i)
                    tree.balance()
                    # vertical edges iterations
                    # every edge is object - two points, one edge
                    for v in vec_:
                        if not v: continue
                        # sort vertices by Z value
                        # find two vertices - one lower, two upper
                        vlist = [v[0], v[1]]
                        vlist.sort(key=lambda x: x[2], reverse=False)
                        # flip if coplanar to enemy plane
                        # flip plane coplanar
                        if vec_cont:
                            fliped = self.get_coplanar(v[0], loc_cont,
                                                       norm_cont, vec_cont)
                        else:
                            fliped = False
                        shortedge = (vlist[1] - vlist[0]).length
                        if fliped:
                            two, one = vlist
                        else:
                            one, two = vlist
                        # coplanar to owner
                        cop = abs(D2P(one, l, n))
                        # defining bounds
                        inside = one[0]<m1x and one[0]>m2x and one[1]<m1y and one[1]>m2y \
                                 and one[2]<=m1z and one[2]>=m2z
                        # if in bounds and coplanar do:
                        #print(self.name,l, cop, inside)
                        if cop < threshold_coplanar and inside and shortedge > thick * threshold:
                            '''
                            huge calculations. if we can reduce...
                            '''
                            # find shift for thickness in sockets
                            diry = two - one
                            diry.normalize()
                            # solution for vertical wafel - cool but not in diagonal case
                            # angle = radians(degrees(atan(n.y/n.x))+90)
                            dirx_ = self.rotation_on_axis(diry, n, radians(90))
                            dirx = dirx_ * thick_2
                            # вектор, индекс, расстояние
                            # запоминаем порядок находим какие удалить рёбра
                            # делаем выборку левая-правая точка
                            nearv_1, near_1 = tree.find(one)[:2]
                            nearv_2, near_2 = tree.find(two)[:2]
                            # indexes of two nearest points
                            # удалить рёбра что мешают спать заодно
                            en_0, en_1, de1 = self.calc_indexes(edgp, near_1)
                            deledges1.extend(de1)
                            en_2, en_3, de2 = self.calc_indexes(edgp, near_2)
                            deledges2.extend(de2)
                            # print(vecp, one, dirx, en_0, en_1)
                            # left-right indexes and vectors
                            # с учётом интерполяций по высоте
                            l1, r1, lz1, rz1 = \
                                    self.calc_leftright(vecp, one, dirx, en_0, en_1, thick_2, diry)
                            l2, r2, lz2, rz2 = \
                                    self.calc_leftright(vecp, two, dirx, en_2, en_3, thick_2, diry)
                            # print(left2, right2, l2, r2, lz2, rz2)
                            # средняя точка и её смещение по толщине материала
                            three = (one - two) / 2 + two

                            # rounded section
                            if self.rounded:
                                '''рёбра'''
                                # пазы формируем независимо от верх низ

                                outeob1 = [[lenvep + k + 8, lenvep + k],
                                           [lenvep + k + 1, lenvep + k + 2],
                                           [lenvep + k + 2, lenvep + k + 3],
                                           [lenvep + k + 3, lenvep + k + 4],
                                           [lenvep + k + 4, lenvep + k + 5],
                                           [lenvep + k + 5, lenvep + k + 6],
                                           [lenvep + k + 6, lenvep + k + 7],
                                           [lenvep + k + 7, lenvep + k + 8],
                                           [lenvep + k + 9, lenvep + k + 1]]

                                outeob2 = [[lenvep + k, lenvep + k + 1],
                                           [lenvep + k + 1, lenvep + k + 2],
                                           [lenvep + k + 2, lenvep + k + 3],
                                           [lenvep + k + 3, lenvep + k + 4],
                                           [lenvep + k + 4, lenvep + k + 5],
                                           [lenvep + k + 5, lenvep + k + 6],
                                           [lenvep + k + 6, lenvep + k + 7],
                                           [lenvep + k + 7, lenvep + k + 8],
                                           [lenvep + k + 8, lenvep + k + 9]]
                                # наполнение списков lenvep = length(vecp)
                                newinds1.extend([[l1, lenvep + k],
                                                 [lenvep + k + 9, r1]])
                                newinds2.extend([[l2, lenvep + k + 9],
                                                 [lenvep + k, r2]])
                                '''Вектора'''
                                round1 = diry * thick_3
                                round2 = diry * thick_3 * sinuso30
                                round2_ = dirx / 3 + dirx * (2 * sinuso60 / 3)
                                round3 = diry * thick_3 * sinuso60_minus
                                round3_ = dirx / 3 + dirx * (2 * sinuso30 / 3)
                                round4 = dirx / 3
                                vupperob.extend([
                                    lz2, three + round1 - dirx,
                                    three + round2 - round2_,
                                    three + round3 - round3_, three - round4,
                                    three + round4, three + round3 + round3_,
                                    three + round2 + round2_,
                                    three + round1 + dirx, rz2
                                ])
                                vlowerob.extend([
                                    rz1, three - round1 - dirx,
                                    three - round2 - round2_,
                                    three - round3 - round3_, three - round4,
                                    three + round4, three - round3 + round3_,
                                    three - round2 + round2_,
                                    three - round1 + dirx, lz1
                                ])
                                k += 10

                            # streight section
                            else:
                                '''рёбра'''
                                # пазы формируем независимо от верх низ
                                outeob1 = [[lenvep + k, lenvep + k + 1],
                                           [lenvep + k + 1, lenvep + k + 2],
                                           [lenvep + k + 2, lenvep + k + 3]]
                                outeob2 = [[lenvep + k, lenvep + k + 1],
                                           [lenvep + k + 1, lenvep + k + 2],
                                           [lenvep + k + 2, lenvep + k + 3]]
                                # наполнение списков lenvep = length(vecp)
                                newinds1.extend([[l1, lenvep + k],
                                                 [lenvep + k + 3, r1]])
                                newinds2.extend([[l2, lenvep + k + 3],
                                                 [lenvep + k, r2]])
                                '''Вектора'''
                                vupperob.extend(
                                    [lz2, three - dirx, three + dirx, rz2])
                                vlowerob.extend(
                                    [rz1, three + dirx, three - dirx, lz1])
                                k += 4
                            newinds1.extend(outeob1)
                            newinds2.extend(outeob2)

                            # circles to bing panels section
                            if self.bindCircle:
                                CP = self.circl_place
                                if CP == 'Midl':
                                    crcl_cntr = IL2P(one, two, Vector(
                                        (0, 0, 0)), Vector((0, 0, -1)))
                                elif CP == 'Up' and not fliped:
                                    crcl_cntr = two - diry * self.circle_rad * 2
                                elif CP == 'Down' and not fliped:
                                    crcl_cntr = one + diry * self.circle_rad * 2
                                elif CP == 'Up' and fliped:
                                    crcl_cntr = one + diry * self.circle_rad * 2
                                elif CP == 'Down' and fliped:
                                    crcl_cntr = two - diry * self.circle_rad * 2
                                # forgot howto 'else' in line iteration?
                                outeob1 = [[
                                    lenvep + k + i, lenvep + k + i + 1
                                ] for i in range(0, 11)]
                                outeob1.append([lenvep + k, lenvep + k + 11])
                                outeob2 = [[
                                    lenvep + k + i, lenvep + k + i + 1
                                ] for i in range(12, 23)]
                                outeob2.append(
                                    [lenvep + k + 12, lenvep + k + 23])
                                newinds1.extend(outeob1 + outeob2)
                                newinds2.extend(outeob1 + outeob2)
                                mat_rot_cir = n.rotation_difference(
                                    Vector((0, 0, 1))).to_matrix().to_4x4()
                                circle_to_add_1 = [vecir*mat_rot_cir+crcl_cntr+ \
                                        dirx_*self.circle_rad for vecir in circle ]
                                circle_to_add_2 = [vecir*mat_rot_cir+crcl_cntr- \
                                        dirx_*self.circle_rad for vecir in circle ]
                                vupperob.extend(circle_to_add_1 +
                                                circle_to_add_2)
                                vlowerob.extend(circle_to_add_1 +
                                                circle_to_add_2)
                                k += 24

                            # TUBE section
                            if vec_tube and not tubes_flag_bed_solution_i_know:
                                for v in vec_tube:
                                    tubeverlength = len(v)
                                    if tubeverlength == 2:
                                        crcl_cntr = IL2P(v[0], v[1], l, n)
                                        if crcl_cntr:
                                            inside = crcl_cntr[0]<m1x and crcl_cntr[0]>m2x and crcl_cntr[1]<m1y \
                                                 and crcl_cntr[1]>m2y and crcl_cntr[2]<=m1z and crcl_cntr[2]>=m2z
                                            if inside:
                                                outeob = [[
                                                    lenvep + k + i,
                                                    lenvep + k + i + 1
                                                ] for i in range(0, 23)]
                                                outeob.append([
                                                    lenvep + k, lenvep + k + 23
                                                ])
                                                newinds1.extend(outeob)
                                                newinds2.extend(outeob)
                                                mat_rot_cir = n.rotation_difference(
                                                    Vector(
                                                        (0, 0, 1))).to_matrix(
                                                        ).to_4x4()
                                                circle_to_add = [
                                                    vecir * mat_rot_cir +
                                                    crcl_cntr
                                                    for vecir in circle_tube
                                                ]
                                                vupperob.extend(circle_to_add)
                                                vlowerob.extend(circle_to_add)
                                                k += 24
                                    else:
                                        tubeshift = tubeverlength // 2
                                        crcl_cntr = IL2P(
                                            v[0], v[tubeshift], l, n)
                                        if crcl_cntr:
                                            inside = crcl_cntr[0]<m1x and crcl_cntr[0]>m2x and crcl_cntr[1]<m1y \
                                                 and crcl_cntr[1]>m2y and crcl_cntr[2]<=m1z and crcl_cntr[2]>=m2z
                                            if inside:
                                                outeob = [[
                                                    lenvep + k + i,
                                                    lenvep + k + i + 1
                                                ] for i in range(tubeshift - 1)
                                                          ]
                                                outeob.append([
                                                    lenvep + k,
                                                    lenvep + k + tubeshift - 1
                                                ])
                                                newinds1.extend(outeob)
                                                newinds2.extend(outeob)
                                                for tubevert in range(
                                                        tubeshift):
                                                    tubevert_out = IL2P(
                                                        v[tubevert],
                                                        v[tubevert +
                                                          tubeshift], l, n)
                                                    vupperob.append(
                                                        tubevert_out)
                                                    vlowerob.append(
                                                        tubevert_out)
                                                k += tubeshift

                                tubes_flag_bed_solution_i_know = True
                        elif cop < threshold_coplanar and inside and shortedge <= thick * threshold:
                            vupperob.extend([one, two])
                            vlowerob.extend([one, two])
                            newinds1.append([lenvep + k, lenvep + k + 1])
                            newinds2.append([lenvep + k, lenvep + k + 1])
                            k += 2
                    del tree
                    for e in deledges1:
                        if e in newinds1:
                            newinds1.remove(e)
                    for e in deledges2:
                        if e in newinds2:
                            newinds2.remove(e)
                    if vupperob or vlowerob:
                        outeup.append(newinds2)
                        outelo.append(newinds1)
                        vupper.append(vupperob)
                        vlower.append(vlowerob)
                vupper = Vector_degenerate(vupper)
                vlower = Vector_degenerate(vlower)
                centers = Vector_degenerate([centers])

                if 'vert' in self.outputs:
                    if self.out_up_down == 'Up':
                        out = dataCorrect(vupper)
                    else:
                        out = dataCorrect(vlower)
                    self.outputs['vert'].sv_set(out)
                if 'edge' in self.outputs and self.outputs['edge'].links:
                    if self.out_up_down == 'Up':
                        self.outputs['edge'].sv_set(outeup)
                    else:
                        self.outputs['edge'].sv_set(outelo)
                if 'centers' in self.outputs and self.outputs['centers'].links:
                    self.outputs['centers'].sv_set(centers)
                print(self.name, 'is finishing')
Esempio n. 27
0
 def __init__(self, vertices):
     self.kdt = kdtree.KDTree(len(vertices))
     for i, v in enumerate(vertices):
         self.kdt.insert(v, i)
     self.kdt.balance()
Esempio n. 28
0
def create_corner_vert_groups_vert_lists(bm, height, margin, vert_locs):
    """Return a dict containing lists of BMVerts to be added to vert groups

    Args:
        bm (bmesh): bmesh
        obj (bpy.types.Object): Object
        height (float): height
        margin (float): margin size of untextured bit
        deform_groups (bm.verts.layers.deform): deform groups - correspond to vertex groups
        dict {
            'Leg 1 Inner': list[Vector(3)],
            'Leg 2 Inner': list[Vector(3)],
            'Leg 1 Outer': list[Vector(3)],
            'Leg 2 Outer': list[Vector(3)],
            'Leg 1 End': list[Vector(3)],
            'Leg 2 End': list[Vector(3)]} : Locations of bottom verts in each group

    Returns:
        dict {
            'Leg 1 Inner': list[BMVert],
            'Leg 2 Inner': list[BMVert],
            'Leg 1 Outer': list[BMVert],
            'Leg 2 Outer': list[BMVert],
            'Leg 1 End': list[BMVert],
            'Leg 2 End': list[BMVert]} : verts in each group
    """
    # sides
    sides = {
        'Leg 1 Inner': vert_locs['Leg 1 Inner'],
        'Leg 2 Inner': vert_locs['Leg 2 Inner'],
        'Leg 1 Outer': vert_locs['Leg 1 Outer'],
        'Leg 2 Outer': vert_locs['Leg 2 Outer']
    }
    vert_groups = {}

    # create kdtree
    size = len(bm.verts)
    kd = kdtree.KDTree(size)

    for i, v in enumerate(bm.verts):
        kd.insert(v.co, i)

    kd.balance()

    for key, value in sides.items():
        vert_group = []
        for loc in value:
            bottom_vert_co, index, dist = kd.find(loc)
            verts = select_verts_in_bounds(lbound=bottom_vert_co,
                                           ubound=(bottom_vert_co[0],
                                                   bottom_vert_co[1],
                                                   bottom_vert_co[2] + height),
                                           buffer=margin / 2,
                                           bm=bm)
            vert_group.extend(verts)
        vert_groups[key] = vert_group

        bm_deselect_all(bm)

    # ends
    ends = {
        'Leg 1 End': vert_locs['Leg 1 End'],
        'Leg 2 End': vert_locs['Leg 2 End']
    }

    for key, value in ends.items():
        v1_co, v1_index, dist = kd.find(value[0])
        v2_co, v2_index, dist = kd.find(value[1])

        bm.verts.ensure_lookup_table()
        v1 = bm.verts[v1_index]
        v2 = bm.verts[v2_index]

        # select shortest path
        nodes = bm_shortest_path(bm, v1, v2)
        node = nodes[v2]

        for e in node.shortest_path:
            e.select_set(True)
        bm.select_flush(True)

        verts = [v for v in bm.verts if v.select]
        selected_verts = []

        for v in verts:
            selected = select_verts_in_bounds(
                v.co, (v.co[0], v.co[1], v.co[2] + height), margin / 2, bm)
            selected_verts.extend(selected)

        vert_groups[key] = selected_verts
        bm_deselect_all(bm)

    # bottom
    # leg 1
    inner_locs = vert_locs['Leg 1 Inner'][::-1]
    outer_locs = vert_locs['Leg 1 Outer']

    selected_verts = []
    i = 0
    while i < len(outer_locs) and i < len(inner_locs):
        v1_co, v1_index, dist = kd.find(inner_locs[i])
        v2_co, v2_index, dist = kd.find(outer_locs[i])

        bm.verts.ensure_lookup_table()
        v1 = bm.verts[v1_index]
        v2 = bm.verts[v2_index]

        nodes = bm_shortest_path(bm, v1, v2)
        node = nodes[v2]

        for e in node.shortest_path:
            e.select_set(True)
        bm.select_flush(True)

        verts = [v for v in bm.verts if v.select]
        selected_verts.extend(verts)
        i += 1

    vert_groups['Leg 1 Bottom'] = selected_verts
    bm_deselect_all(bm)

    # leg 2
    inner_locs = vert_locs['Leg 2 Inner'][::-1]
    outer_locs = vert_locs['Leg 2 Outer']

    selected_verts = []
    i = 0
    while i < len(inner_locs) and i < len(outer_locs):
        v1_co, v1_index, dist = kd.find(inner_locs[i])
        v2_co, v2_index, dist = kd.find(outer_locs[i])

        bm.verts.ensure_lookup_table()
        v1 = bm.verts[v1_index]
        v2 = bm.verts[v2_index]

        nodes = bm_shortest_path(bm, v1, v2)
        node = nodes[v2]

        for e in node.shortest_path:
            e.select_set(True)
        bm.select_flush(True)

        verts = [v for v in bm.verts if v.select]
        selected_verts.extend(verts)
        i += 1
    vert_groups['Leg 2 Bottom'] = selected_verts
    # assign_verts_to_group(selected_verts, obj, deform_groups, 'Leg 2 Bottom')

    # top
    # leg 1
    inner_locs = vert_locs['Leg 1 Inner'][::-1]
    outer_locs = vert_locs['Leg 1 Outer']

    leg_1_top_verts = []
    i = 0
    while i < len(inner_locs) and i < len(outer_locs):
        v1 = select_verts_in_bounds(
            (inner_locs[i][0], inner_locs[i][1], inner_locs[i][2] + height),
            (inner_locs[i][0], inner_locs[i][1], inner_locs[i][2] + height),
            margin / 2, bm)
        v2 = select_verts_in_bounds(
            (outer_locs[i][0], outer_locs[i][1], outer_locs[i][2] + height),
            (outer_locs[i][0], outer_locs[i][1], outer_locs[i][2] + height),
            margin / 2, bm)

        nodes = bm_shortest_path(bm, v1[0], v2[0])
        node = nodes[v2[0]]

        for e in node.shortest_path:
            e.select_set(True)
        bm.select_flush(True)

        verts = [v for v in bm.verts if v.select]
        leg_1_top_verts.extend(verts)
        i += 1
    vert_groups['Leg 1 Top'] = leg_1_top_verts
    bm_deselect_all(bm)

    # leg 2
    inner_locs = vert_locs['Leg 2 Inner'][::-1]
    outer_locs = vert_locs['Leg 2 Outer']

    leg_2_top_verts = []
    i = 0
    while i < len(inner_locs) and i < len(outer_locs):
        v1 = select_verts_in_bounds(
            (inner_locs[i][0], inner_locs[i][1], inner_locs[i][2] + height),
            (inner_locs[i][0], inner_locs[i][1], inner_locs[i][2] + height),
            margin / 2, bm)
        v2 = select_verts_in_bounds(
            (outer_locs[i][0], outer_locs[i][1], outer_locs[i][2] + height),
            (outer_locs[i][0], outer_locs[i][1], outer_locs[i][2] + height),
            margin / 2, bm)

        nodes = bm_shortest_path(bm, v1[0], v2[0])
        node = nodes[v2[0]]

        for e in node.shortest_path:
            e.select_set(True)
        bm.select_flush(True)

        verts = [v for v in bm.verts if v.select]
        leg_2_top_verts.extend(verts)
        i += 1
    vert_groups['Leg 2 Top'] = leg_2_top_verts
    bm_deselect_all(bm)

    return vert_groups
Esempio n. 29
0
    def execute(self, context):
        sourceObj = context.active_object
        TargetObjs = [
            obj for obj in context.selected_objects
            if obj != sourceObj and obj.type == 'MESH'
        ]

        if not TargetObjs:
            self.report({
                'ERROR'
            }, 'You seed to select two mesh objects (source then target that will receive vert order)! Cancelling'
                        )
            return {'CANCELLED'}

        bm = bmesh.new()  # load mesh
        bm.from_mesh(sourceObj.data)
        src_obj_kd_verts = kdtree.KDTree(len(bm.verts))
        for i, v in enumerate(bm.verts):
            src_obj_kd_verts.insert(v.co, i)
        src_obj_kd_verts.balance()

        src_obj_kd_edges = kdtree.KDTree(len(bm.edges))
        for i, edge in enumerate(bm.edges):
            src_obj_kd_edges.insert((edge.verts[0].co + edge.verts[1].co) / 2,
                                    i)
        src_obj_kd_edges.balance()

        src_obj_kd_faces = kdtree.KDTree(len(bm.faces))
        for i, f in enumerate(bm.faces):
            src_obj_kd_faces.insert(f.calc_center_median(), i)
        src_obj_kd_faces.balance()
        bm.free()
        processedVertsIdDict = {}
        processedEdgesIdDict = {}
        processedFacesIdDict = {}
        for target in TargetObjs:
            copiedCount = 0
            processedVertsIdDict.clear()
            bm = bmesh.new()  # load mesh
            bm.from_mesh(target.data)
            for vert in bm.verts:
                co, index, dist = src_obj_kd_verts.find(vert.co)
                if dist < self.delta:  # delta
                    copiedCount += 1
                    vert.index = index
                    processedVertsIdDict[vert] = index

            for edge in bm.edges:
                co, index, dist = src_obj_kd_edges.find(
                    (edge.verts[0].co + edge.verts[1].co) / 2)
                if dist < self.delta:  #delta
                    copiedCount += 1
                    edge.index = index
                    processedEdgesIdDict[edge] = index

            for face in bm.faces:
                co, index, dist = src_obj_kd_faces.find(
                    face.calc_center_median())
                if dist < self.delta:  #delta
                    copiedCount += 1
                    face.index = index
                    processedFacesIdDict[face] = index

            VOT_OT_PasteVertID.sortOtherVerts(processedVertsIdDict,
                                              processedEdgesIdDict,
                                              processedFacesIdDict, bm)
            bm.verts.sort()
            bm.edges.sort()
            bm.faces.sort()
            bm.to_mesh(target.data)
            bm.free()
            self.report({'INFO'},
                        'Pasted ' + str(copiedCount) + ' vert id\'s ')
        return {"FINISHED"}