Example #1
0
    def triangulate(self, z=0.):
        """Triangulate shape using ear clipping algorithm."""
        model = Model()
        v_list = [np.array([v[0], v[1], z]) for v in self._vertices]
        v_list_len = len(v_list)
        while v_list_len > 3:
            for i, v in enumerate(v_list):
                # print(f'processing {i}, {v}')
                v0 = v_list[(i - 1) % len(v_list)]
                v1 = v_list[(i + 1) % len(v_list)]
                ang = angle(v1 - v, v0 - v)
                #first: find a triangle with a convex corner
                if ang < math.pi:
                    #second: check if no other vertices are inside triangle
                    if not any(not vm.equal(vv, v) and not vm.equal(vv, v0)
                               and not vm.equal(vv, v1)
                               and self.__point_in_triangle(vv, v0, v, v1)
                               for vv in v_list):
                        model.add_face([v0, v, v1])
                        v_list.pop(i)
                        break
            if v_list_len == len(v_list):
                raise RuntimeError(
                    'Ear clipping failed to find vertice tripple to triangulate'
                )
            v_list_len = len(v_list)

        model.add_face(v_list)
        model._update()
        return model
Example #2
0
    def __divide_all(self, vertices, triangles):
        # Subdivide each triangle in the old approximation and normalize
        #  the new points thus generated to lie on the surface of the unit
        #  sphere.
        # Each input triangle with vertices labelled [0,1,2] as shown
        #  below will be turned into four new triangles:
        #
        #            Make new points
        #                 a = (0+2)/2
        #                 b = (0+1)/2
        #                 c = (1+2)/2
        #        1
        #       /\        Normalize a, b, c
        #      /  \
        #    b/____\ c    Construct new triangles
        #    /\    /\       t1 [0,b,a]
        #   /  \  /  \      t2 [b,1,c]
        #  /____\/____\     t3 [a,b,c]
        # 0      a     2    t4 [a,c,2]

        v = []
        for tri in triangles:
            v0 = vertices[tri[0]]
            v1 = vertices[tri[1]]
            v2 = vertices[tri[2]]
            a = vm.unit_vector((v0 + v2) * 0.5)
            b = vm.unit_vector((v0 + v1) * 0.5)
            c = vm.unit_vector((v1 + v2) * 0.5)
            v += [v0, b, a, b, v1, c, a, b, c, a, c, v2]
        return v, np.arange(len(v)).reshape((-1, 3))
Example #3
0
def cost_func(path):
    """ This cost function just returns the linear distance between the nodes (assumed to be spatial
            nodes)"""
    cost = 0
    for i in range(1, len(path)):
        cost += VecMath.length(
            VecMath.sub(path[i - 1].position, path[i].position))
    return cost
Example #4
0
    def test_get_rotation_mtx(self):
        a = np.array([1., 0., 0.])
        b = np.array([0., 1., 0.])
        rot = VecMath.rotate_fromto_matrix(a, b)
        self.assertIsNotNone(rot)

        a2 = rot.__matmul__(a)
        self.assertNotEqual(VecMath.angle_between(a, b), 0.0)
        self.assertEqual(VecMath.angle_between(a2, b), 0.0)
Example #5
0
    def test_get_rotation_mtx_equal_vecs(self):
        """ edge case: would normaly break rot mtx. use identity mtx instead """
        a = np.array([1., 0., 0.])
        b = np.array([1., 0., 0.])
        rot = VecMath.rotate_fromto_matrix(a, b)
        self.assertIsNotNone(rot)

        a2 = rot.__matmul__(a)
        self.assertEqual(VecMath.angle_between(a2, b), 0.0)
Example #6
0
 def is_equal(self, other):
     if isinstance(other, Edge):
         return (self.v0_id == other.v0_id and self.v1_id
                 == other.v1_id) or (self.v1_id == other.v0_id
                                     and self.v0_id == other.v1_id)
     if isinstance(other, list):
         return (vm.equal(self._v0, other[0]) and vm.equal(
             self._v1, other[1])) or (vm.equal(self._v1, other[0])
                                      and vm.equal(self._v0, other[1]))
     return False
Example #7
0
    def test_dist_point_to_line2(self):
        line_p = np.array([0., 0., 0.])
        line_dir = np.array([1., 1., 1.])

        dist = VecMath.dist_point_to_line(line_p, line_dir,
                                          np.array([0., .2, .5]))
        self.assertEqual(dist, 0.35590260840104376)
Example #8
0
    def test_dist_point_to_line(self):
        line_p = np.array([0., 0., 0.])
        line_dir = np.array([1., 0., 0.])

        dist = VecMath.dist_point_to_line(line_p, line_dir,
                                          np.array([-1., 2., 0.]))
        self.assertEqual(dist, 2.)
Example #9
0
def embed_label(model, face, side, label, glyph):
    # transform face to shape (into which we will embed the label)
    transform = MtxMath.conv_to_euclid(VecMath.rotate_fromto_matrix(face._norm, np.array([0., 0., 1.])))
    vertices = [transform * euclid.Point3(v[0], v[1], v[2]) for v in face._vertices]
    target_path = svg.Path.from_shape(svg.Shape([np.array([v[0], v[1]]) for v in vertices]))

    # render label into path
    label_path = svg.Path.combine([(glyph[int(c)], np.array([1., 0.])) for c in label])

    # move/scale label to fit into target triangle
    p, s, r = fit_rect_in_triangle(vertices, side, label_path._bbox)
    label_path.scale(s[0], s[1])
    pivot = label_path._bbox._center+np.array([0, label_path._bbox._size[1]*-.5])
    label_path.rotate(r, anchor=pivot)
    label_path.translate(p-pivot)

    # embed the label
    embedded_model = target_path.embed([label_path.triangulate(z=vertices[0].z)], group_name='svg', z=vertices[0].z)
    embedded_model.transform(transform.inverse())

    # (optional) extrude the label
    embedded_model.get_group('svg')._material._diffuse = [1., 0., 0.]
    embedded_model.extrude(-.5, faces=embedded_model.get_group('svg')._faces)

    # replace initial face with new 'labeled face'
    model.remove_face(face)
    model.merge(embedded_model)

    return embedded_model
Example #10
0
 def angle_between(self, other):
     """ Return the angle in radians between this plane and another plane or vector """
     if isinstance(other, Plane):
         other_v = other._norm
     elif len(other) == 3:
         # elif isinstance(other, np.array) and len(other) == 3:
         other_v = other
     return vm.angle_between(self._norm, other_v)
Example #11
0
 def calculate_vertice_norms(self):
     self._vertices_norm = []
     for v_id in range(len(self._vertices)):
         v_norm = np.array([0.,0.,0.])
         for face in self._faces:
             if face.contains_vertex(v_id):
                 v_norm += face._norm
         self._vertices_norm.append(VecMath.unit_vector(v_norm))
Example #12
0
def get_path_from_face(face):
    transform = MtxMath.conv_to_euclid(
        VecMath.rotate_fromto_matrix(face._norm, np.array([0., 0., 1.])))
    vertices = [
        transform * euclid.Point3(v[0], v[1], v[2]) for v in face._vertices
    ]
    path = svg.Path.from_shape(
        svg.Shape([np.array([v[0], v[1]]) for v in vertices]))
    return path, transform
def get_first_plane(vertex, faces):
    """ First plane: Find the plane which center is closest to the vertex """
    min_dist = sys.float_info.max
    min_idx = None
    for idx, face in enumerate(faces):
        dist = vm.dist_point_to_point(vertex, face._center)
        if dist < min_dist:
            min_idx = idx
            min_dist = dist
    # print(f'ref_plane #1: {min_idx} -> ref: {faces[min_idx]._id}')
    return min_idx
Example #14
0
 def createJoints(self):
     if not self.m_userJoints:
         self.m_bindJoints = []
         startPos = cmds.xform(self.m_parent1, q=1, t=1, ws=1)
         endPos = cmds.xform(self.m_parent2, q=1, t=1, ws=1)
         stepVec = vec.divide(
             vec.subtract(endPos, startPos), 
             self.m_numJoints - 1
             )
         currentPos = startPos
         for i in range(self.m_numJoints):
             newJoint = self.m_name+"_"+str(i)+"_BIND_JNT"
             newJoint = cmds.joint(n=newJoint, p=currentPos)
             cmds.setAttr("%s.radius" %(newJoint), 0.1)
             self.m_bindJoints.append(newJoint)
             currentPos = vec.add(currentPos, stepVec)
         #fix orientations
         cmds.joint(
             self.m_bindJoints[0], 
             e=1, 
             oj="xyz", 
             sao = "yup", 
             ch=1, 
             zso=1
             )
     else:
         # Duplicate joints and rename
         newJoints = cmds.duplicate(self.m_userJoints[0], rc=1)
         for i in range(len(newJoints)):
             newJoint = "%s_%d_BIND_JNT" %(self.m_name, i)
             newJoints[i] = cmds.rename(newJoints[i], newJoint)
         self.m_bindJoints = newJoints
     #Put it in the right group
     cmds.parent(self.m_bindJoints[0], self.m_group)
     rc.addToLayer(self.m_sceneData, "ref", self.m_bindJoints[0])
     #Strip sets
     for joint in self.m_bindJoints:
         rc.stripSets(joint)
     #Add all except first and last to bind set
     for joint in self.m_bindJoints[:-1]:
         rc.addToSet(self.m_sceneData, "bind", joint)
Example #15
0
 def simplify(self, epsilon=.00001):
     face_count_before = len(self._faces)
     for face in list(self._faces): # very important to copy the list first as we modify while iteration is not done yet
         for neighbour in face._neighbour_faces:
             if VecMath.angle_between(face._norm, neighbour._norm) < epsilon:
                 v_ids = face.merge_face_vids(neighbour)
                 # as we are modifying the list while iterating though it we need this test to check if the consolidation of this tri was already done
                 if v_ids and len(face._vertex_ids) < len(v_ids):
                     self.remove_face(face)
                     self.remove_face(neighbour)
                     self.add_face([self._vertices[id] for id in v_ids], group=face._group, tags=set(face._tags + neighbour._tags))
     self._update()
     print(f'Simplify: Face count {face_count_before} before -> {len(self._faces)} after')
Example #16
0
def write(model, filename, orientation_vec=None):
    """Rotate and center object to lay flat on the heat-bead"""
    model._update()

    if orientation_vec is None:
        transform = euclid.Matrix4.new_translate(-model._center[0],
                                                 -model._center[1],
                                                 -model._center[2])
    else:
        transform = MtxMath.conv_to_euclid(
            VecMath.rotate_fromto_matrix(orientation_vec,
                                         np.array([0., 0., -1.])))
        n = transform * euclid.Point3(-model._center[0], -model._center[1],
                                      -model._center[2])
        transform = euclid.Matrix4.new_translate(n.x, n.y, n.z) * transform

    write_obj(model, filename, transform=transform)
Example #17
0
 def test_angle_between(self):
     self.assertEqual(VecMath.angle_between((1, 0, 0), (0, 1, 0)),
                      1.5707963267948966)
     self.assertEqual(VecMath.angle_between((1, 0, 0), (1, 0, 0)), 0.0)
     self.assertEqual(VecMath.angle_between((1, 0, 0), (-1, 0, 0)),
                      3.141592653589793)
Example #18
0
    model.remove_face(face)
    model.merge(embedded_model)

    return embedded_model

if __name__ == "__main__":
    radius = 100.
    sphere = primitives.Sphere(radius)
    obj_model = sphere.triangulate(recursion_level=2)

    for iter in range(0,4):
        print(f'noise iteration({iter})')
        for idx, vertex in enumerate(obj_model._vertices):
            l = min([edge.length for edge in obj_model.get_edges_with_vertex(idx)]) * .1
            rnd_d = get_random_norm()
            dir = VecMath.unit_vector(vertex)
            transf = MtxMath.conv_to_euclid(VecMath.rotate_fromto_matrix(np.array([0., 0., 1.]), dir))
            tv = transf * (rnd_d*euclid.Vector3(l,l,10))
            vertex += tv

    # sphere_model.triangulate()
    ObjExporter.write(obj_model, f'./export/_sphere_noise.obj')

    print(f'Faces: {len(obj_model._faces)}')
    print(f'Vertices: {len(obj_model._vertices)}')
    bbox_size = obj_model._size
    print(f'Boundingbox: [{bbox_size[0]}, {bbox_size[1]}, {bbox_size[2]}]')

    target_lid_size = 100. #mm^2
    faceted_model = Model()
Example #19
0
    for face in dt.exportTriangles():
        obj_model.add_face([vertices3d[face[0]], vertices3d[face[1]], vertices3d[face[2]]])

    # calculate heights depending on point density
    obj_model._update()
    v_heights = []
    for idx, vertex in enumerate(obj_model._vertices):
        vertex_conntected = []
        connected_faces = obj_model.get_faces_with_vertex(idx)
        for face in connected_faces:
            for edge in face._edges:
                if edge.v0_id == idx:
                    vertex_conntected.append(tuple([idx, edge.v1_id]))
                elif edge.v1_id == idx:
                    vertex_conntected.append(tuple([idx, edge.v0_id]))
        dist = 0
        for c in vertex_conntected:
            dist = dist + VecMath.dist_point_to_point(obj_model._vertices[c[0]], obj_model._vertices[c[1]])
        v_heights.append(dist / float(len(vertex_conntected)))

    min_z = min(v_heights)
    max_z = max(v_heights)
    f = 1. / (max_z)

    for idx, vertex in enumerate(obj_model._vertices):
        obj_model._vertices[idx][VecMath._Z] = (1. - ((v_heights[idx]-min_z) / max_z)) * 100
        print(obj_model._vertices[idx][VecMath._Z])

    # export to obj file
    obj_model._update()
    ObjExporter.write(obj_model, f'./export/_delanay2d.obj')
Example #20
0
    def __init__(self, graph, path=None):
        self.root = tk.Tk()
        self.root.geometry("1200x800")
        self.root.config(bg='white')
        self.canvas = tk.Canvas(width=1200, height=800)
        self.canvas.config(bg='white')
        self.radius = 15
        for node in graph.nodes:
            pos = node.position
            self.canvas.create_oval(pos[0] - self.radius, pos[1] - self.radius, pos[0] + self.radius, pos[1] + self.radius, fill='red')
            self.canvas.create_text(pos[0], pos[1], text=str(node.id), anchor='center')
            for succ in node.successors:
                to_succ = VecMath.normal(VecMath.sub(succ.position, node.position))
                arrow_start = VecMath.add(node.position, VecMath.multiply(to_succ, self.radius))
                arrow_end = VecMath.sub(succ.position, VecMath.multiply(to_succ, self.radius))
                self.canvas.create_line(arrow_start[0], arrow_start[1], arrow_end[0], arrow_end[1], arrow=tk.LAST)

        if path is not None:
            self.path_lines = []
            for i in range(1, len(path)):
                a_to_b = VecMath.normal(VecMath.sub(path[i].position, path[i - 1].position))
                arrow_start = VecMath.add(path[i - 1].position, VecMath.multiply(a_to_b, self.radius))
                arrow_end = VecMath.sub(path[i].position, VecMath.multiply(a_to_b, self.radius))
                self.path_lines.append(
                    self.canvas.create_line(arrow_start[0], arrow_start[1], arrow_end[0], arrow_end[1], arrow=tk.LAST,
                                            dash=(2, 2), fill='yellow', width=10))
            self.canvas.update()

        self.canvas['bg'] = 'green'
        self.canvas.pack()
        self.root.mainloop()
Example #21
0
 def test_unit_vector(self):
     self.assertEqual(
         np.linalg.norm(VecMath.unit_vector(np.array([1., 2., 3.]))), 1.)
Example #22
0
 def calculate_norm(self, vertices):
     self._norm = np.cross(
         vertices[self._vertex_ids[1]] - vertices[self._vertex_ids[0]],
         vertices[self._vertex_ids[2]] - vertices[self._vertex_ids[0]])
     self._norm = VecMath.unit_vector(self._norm)
    d = euclid.Vector3(random.uniform(0, 1), random.uniform(0, 1),
                       0.).normalize()
    # d = euclid.Vector3(0., 0., 0.)
    # d.x = random.uniform(-1, 1)
    # d.y = random.uniform(-1, 1)
    # d.z = random.uniform(-.1, .1)
    # d.z = 1.
    return d


if __name__ == "__main__":
    radius = 100.
    sphere = primitives.Sphere(radius)
    sphere_model = sphere.triangulate(recursion_level=2)

    for iter in range(0, 4):
        print(f'noise iteration({iter})')
        for idx, vertex in enumerate(sphere_model._vertices):
            l = min([
                edge.length for edge in sphere_model.get_edges_with_vertex(idx)
            ]) * .1
            rnd_d = get_random_norm()
            dir = vm.unit_vector(vertex)
            transf = MtxMath.conv_to_euclid(
                vm.rotate_fromto_matrix(np.array([0., 0., 1.]), dir))
            tv = transf * (rnd_d * euclid.Vector3(l, l, 10))
            vertex += tv

    # sphere_model.triangulate()
    ObjExporter.write(sphere_model, f'./export/_sphere_noise.obj')
Example #24
0
 def from_points(cls, p0, p1, p2, norm_dir=1.):
     """ Create a plane from 3 points that span the plane """
     return Plane(p0, vm.unit_vector(np.cross(p1 - p0, p2 - p0) * norm_dir))
Example #25
0
 def get_identical_vertices(self, other):
     res = [(u, v) for u, v in list(
         itertools.product(range(len(self._vertices)),
                           range(len(other._vertices))))
            if vm.equal(self._vertices[u], other._vertices[v])]
     return res
Example #26
0
    def createControls(self):
        #If no blend control is speified add one
        if not self.m_blendControl:
            self.m_blendControl = cmds.circle(n=self.m_name+"Blend_CTRL")[0]
            cmds.parent(self.m_blendControl, self.m_group)
            self.m_allControls.append(self.m_blendControl)
            rc.addToControlDict(
                self.m_allControls,
                "%s_StretchChainCtrl" %(self.m_baseName),
                self.m_blendControl
                )

        cmds.addAttr(
            self.m_blendControl,
            ln=self.m_attrHeading,
            k=True,
            at = "enum",
            en = "---------:"
            )

        if self.m_isAutoBend:
            cmds.addAttr(
                self.m_blendControl, 
                ln=self.m_blendAttrName, 
                k=1, min=0, max=1, dv=0
                )
            blendNodeAttr = self.m_blendControl+"."+self.m_blendAttrName
            oppBlendNodeAttr = rc.create1MinusNode(
                blendNodeAttr, 
                self.m_name+"OppBlend_CTRL" 
                )
        
        self.m_controls = []
        self.m_parentCtrls = []
        self.m_pointCtrls = []
        startPos = cmds.xform(self.m_parent1, q=1, t=1, ws=1)
        endPos = cmds.xform(self.m_parent2, q=1, t=1, ws=1)
        stepVec = vec.divide(
            vec.subtract(endPos, startPos), 
            self.m_numCtrls + 1
            )
        currentPos = vec.add(startPos, stepVec)
        for i in range(self.m_numCtrls):
            newCtrl = self.m_name+"_"+str(i)+"_CTRL"
            parentCtrl = self.m_name+"_"+str(i)+"_parent_CTRL"
            pointCtrl = self.m_name+"_"+str(i)+"_point_CTRL"
            
            newCtrl = cmds.spaceLocator(n=newCtrl)[0]
            self.m_controls.append(newCtrl)
            cmds.parent(newCtrl, self.m_group)
            cmds.xform(newCtrl, t=currentPos, ws=1)
            newCtrlGroups = rg.add3Groups(newCtrl, ["_SDK", "_CONST", "_0"])
            
            if self.m_isAutoBend:
                parentCtrl = cmds.duplicate(newCtrl, n=parentCtrl)[0]
                cmds.parent(parentCtrl, newCtrlGroups[2])
                #cmds.setAttr(parentCtrl+".visibility", 0)
                pointCtrl = cmds.duplicate(newCtrl, n=pointCtrl)[0]
                cmds.parent(pointCtrl, newCtrlGroups[2])
                #cmds.setAttr(pointCtrl+".visibility", 0)

                rc.addToLayer(self.m_sceneData, "hidden", [parentCtrl, pointCtrl])

                #Create blend between parent and point setups
                blendConst = cmds.pointConstraint(parentCtrl, newCtrlGroups[1])
                cmds.connectAttr(blendNodeAttr, blendConst[0]+"."+parentCtrl+"W0")
                blendConst = cmds.pointConstraint(pointCtrl, newCtrlGroups[1])
                cmds.connectAttr(oppBlendNodeAttr, blendConst[0]+"."+pointCtrl+"W1")
                
                
                self.m_parentCtrls.append(parentCtrl)
                self.m_pointCtrls.append(pointCtrl)
                
                grandParent = cmds.listRelatives(self.m_parent1, p=1)
                if grandParent == None or not self.m_isParentBend:
                    grandParent = self.m_parent1
                
                parentConst = rc.applyWeightedConstraint(
                    grandParent, 
                    parentCtrl, 
                    self.m_parent2, 
                    cmds.parentConstraint
                    )
                pointConst = rc.applyWeightedConstraint(
                    self.m_parent1, 
                    pointCtrl, 
                    self.m_parent2, 
                    cmds.pointConstraint
                    )
            cmds.aimConstraint(
                    self.m_parent2,
                    newCtrlGroups[1]
                    )
            currentPos = vec.add(currentPos, stepVec)
            #lock attrs
            cmds.setAttr(newCtrl+".rotate", l=1)
            cmds.setAttr(newCtrl+".scale", l=1)
        rc.addToLayer(self.m_sceneData, "detailCtrl", self.m_controls)
        # Add controls
        i=0
        for control in self.m_controls:
            rc.addToControlDict(self.m_allControls, "%s_%d_detail" %(self.m_baseName, i), control)
            i+=1
Example #27
0
	def isColliding(self, bX, bY):
		return VecMath.refresh(bX, bY, self.surface)
Example #28
0
def linear_distance_heuristic(path, goal):
    return VecMath.length(VecMath.sub(goal.position, path[-1].position))