Skip to content
Snippets Groups Projects
cad_module.py 4.17 KiB
Newer Older
  • Learn to ignore specific revisions
  • import bpy
    import bmesh
    
    from mathutils import Vector, geometry
    from mathutils.geometry import intersect_line_line as LineIntersect
    from mathutils.geometry import intersect_point_line as PtLineIntersect
    
    
    class CAD_prefs:
        VTX_PRECISION = 1.0e-5
        VTX_DOUBLES_THRSHLD = 0.0001
    
    
    def point_on_edge(p, edge):
        '''
        > p:        vector
        > edge:     tuple of 2 vectors
        < returns:  True / False if a point happens to lie on an edge
        '''
        pt, _percent = PtLineIntersect(p, *edge)
        on_line = (pt-p).length < CAD_prefs.VTX_PRECISION
        return on_line and (0.0 <= _percent <= 1.0)
    
    
    def line_from_edge_intersect(edge1, edge2):
        '''
        > takes 2 tuples, each tuple contains 2 vectors
        - prepares input for sending to intersect_line_line
        < returns output of intersect_line_line
        '''
        [p1, p2], [p3, p4] = edge1, edge2
        return LineIntersect(p1, p2, p3, p4)
    
    
    def get_intersection(edge1, edge2):
        '''
        > takes 2 tuples, each tuple contains 2 vectors
        < returns the point halfway on line. See intersect_line_line
        '''
        line = line_from_edge_intersect(edge1, edge2)
        return ((line[0] + line[1]) / 2)
    
    
    def get_intersection_from_idxs(bm, idx1, ixd2):
        '''
        > takes reference to bm and 2 indices
        < returns intersection or None
        '''
        p1, p2 = coords_tuple_from_edge_idx(bm, idx1)
        p3, p4 = coords_tuple_from_edge_idx(bm, idx2)
        a, b = LineIntersect(p1, p2, p3, p4)
        if (a-b).length < CAD_prefs.VTX_PRECISION:
            return a
    
    
    def test_coplanar(edge1, edge2):
        '''
        the line that describes the shortest line between the two edges
        would be short if the lines intersect mathematically. If this
        line is longer than the VTX_PRECISION then they are either
        coplanar or parallel.
        '''
        line = line_from_edge_intersect(edge1, edge2)
        return (line[0]-line[1]).length < CAD_prefs.VTX_PRECISION
    
    
    def closest_idx(pt, e):
        '''
        > pt:       vector
        > e:        bmesh edge
        < returns:  returns index of vertex closest to pt.
    
        if both points in e are equally far from pt, then v1 is returned.
        '''
        if isinstance(e, bmesh.types.BMEdge):
            ev = e.verts
            v1 = ev[0].co
            v2 = ev[1].co
            distance_test = (v1 - pt).length <= (v2 - pt).length
            return ev[0].index if distance_test else ev[1].index
    
        print("received {0}, check expected input in docstring ".format(e))
    
    
    def closest_vector(pt, e):
        '''
        > pt:       vector
        > e:        2 vector tuple
        < returns:
        pt, 2 vector tuple: returns closest vector to pt
    
        if both points in e are equally far from pt, then v1 is returned.
        '''
        if isinstance(e, tuple) and all([isinstance(co, Vector) for co in e]):
            v1, v2 = e
            distance_test = (v1 - pt).length <= (v2 - pt).length
            return v1 if distance_test else v2
    
        print("received {0}, check expected input in docstring ".format(e))
    
    
    def coords_tuple_from_edge_idx(bm, idx):
        ''' bm is a bmesh representation '''
        return tuple(v.co for v in bm.edges[idx].verts)
    
    
    def vectors_from_indices(bm, raw_vert_indices):
        ''' bm is a bmesh representation '''
        return [bm.verts[i].co for i in raw_vert_indices]
    
    
    def vertex_indices_from_edges_tuple(bm, edge_tuple):
        '''
        > bm:           is a bmesh representation
        > edge_tuple:   contains two edge indices.
        < returns the vertex indices of edge_tuple
        '''
        k = lambda v, w: bm.edges[edge_tuple[v]].verts[w].index
        return [k(i >> 1, i % 2) for i in range(4)]
    
    
    def num_edges_point_lies_on(pt, edges):
        ''' returns the number of edges that a point lies on. '''
        res = [point_on_edge(pt, edge) for edge in [edges[:2], edges[2:]]]
        return len([i for i in res if i])
    
    
    def find_intersecting_edges(bm, pt, idx1, idx2):
        '''
        > pt:           Vector
        > idx1, ix2:    edge indices,
        < returns the list of edge indices where pt is on those edges
        '''
        idxs = [idx1, idx2]
        edges = [coords_tuple_from_edge_idx(bm, idx) for idx in idxs]
        return [idx for edge, idx in zip(edges, idxs) if point_on_edge(pt, edge)]
    
    
    def duplicates(indices):
        return len(set(indices)) < 4
    
    
    def vert_idxs_from_edge_idx(bm, idx):
        edge = bm.edges[idx]
        return edge.verts[0].index, edge.verts[1].index