Beispiel #1
0
def reflect_across_2D_pts(edgepts):
    x1 = edgepts[0][0]
    y1 = edgepts[0][1]
    x2 = edgepts[1][0]
    y2 = edgepts[1][1]

    dx = (x1 - x2)
    if dx == 0:  #Edge is a vertical line
        shift = np.array([[1, 0, 0, -x1], [0, 1, 0, 0], [0, 0, 1, 0],
                          [0, 0, 0, 1]])
        shift2 = np.array([[1, 0, 0, x1], [0, 1, 0, 0], [0, 0, 1, 0],
                           [0, 0, 0, 1]])
        reflect = np.array([[-1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0],
                            [0, 0, 0, 1]])
        r = np.dot(shift2, np.dot(reflect, shift))

        return r

    m = (y1 - y2) / dx
    n = 1 + m * m
    b = y1 - (m * x1)
    a = m * -1
    d = 1 + (m * m)

    #Product of two opposite shifts of b in the y direction and a reflection across y = mx
    shift = np.array([[1, 0, 0, 0], [0, 1, 0, -b], [0, 0, 1, 0], [0, 0, 0, 1]])
    shift2 = np.array([[1, 0, 0, 0], [0, 1, 0, b], [0, 0, 1, 0], [0, 0, 0, 1]])
    reflec = np.array([[1 - 2 * (a * a) / n, -2 * a / n, 0, 0],
                       [-2 * a / n, 1 - 2 / n, 0, 0], [0, 0, 1, 0],
                       [0, 0, 0, 1]])
    return np.dot(shift2, np.dot(reflec, shift))
Beispiel #2
0
    def transform(self, scale=1, angle=0, origin=(0, 0)):
        r = np.array([[np.cos(angle), -np.sin(angle)],
                      [np.sin(angle), np.cos(angle)]]) * scale
        o = np.array([origin] * len(self.pts_2D))

        pts = np.transpose(np.dot(r, np.transpose(np.array(self.pts_2D)))) + o
        self.pts_2D = [tuple(x) for x in np.rows(pts)]
        for (i, d) in enumerate(self.decorations):
            o = np.array([origin] * len(d[0]))
            pts = np.transpose(np.dot(r, np.transpose(np.array(d[0])))) + o
            self.decorations[i] = ([tuple(x) for x in np.rows(pts)], d[1])
Beispiel #3
0
 def get_2D_decorations(self):
     if self.transform_2D is not None:
         edges = []
         for i, e in enumerate(self.decorations):
             if e[1] == "hole":
                 for j in range(len(e[0])):
                     name = self.name + ".d%d.e%d" % (i, j)
                     pt1 = np.dot(self.transform_2D, np.array(list(e[0][j - 1]) + [0, 1]))[0:2]
                     pt2 = np.dot(self.transform_2D, np.array(list(e[0][j]) + [0, 1]))[0:2]
                     # XXX use EdgeType appropriately
                     edges.append([name, pt1, pt2, 1])
             else:
                 name = self.name + ".d%d" % i
                 pt1 = np.dot(self.transform_2D, np.array(list(e[0][0]) + [0, 1]))[0:2]
                 pt2 = np.dot(self.transform_2D, np.array(list(e[0][1]) + [0, 1]))[0:2]
                 edges.append([name, pt1, pt2, e[1]])
         return edges
     return []
Beispiel #4
0
 def place_faces(self, face, edge_from, transform_2D, placed=None, allow_overlap=False):
     """Recursively adds faces to the 2D drawing.
     Args:
         face: the current face being placed
         edge_from: the edge by which to attach the current face
         transform_2D: A tranformation matrix to move the face into its position in 2D space
         placed: dictionary containing metadata about previously placed entities
         allow_overlap: Whether or not to allow two face to be placed on top of each other
     """
     if placed is not None and face in placed['faces']:
         #This face has already been placed, do not place again
         return
     if placed is None:
         #No faces have been placed yet, initialize data structures
         placed = {'faces': [], 'edges': {}, 'overlapping': []}
         check_for_overlap = not allow_overlap
     else:
         #Overlap checking is handled only in top level call
         check_for_overlap = False
     """
     Placing faces involves the notion of "pretransformed" and "transformed" values.
     Pretransformation moves the edge a face is being connected by to the x axis,
     and can be thought of as a face's relative position to its neighbor.
     Transformation moves a face to its absolute position in 2D space.
     """
     if edge_from is not None:
         #Align connected edges
         pretransform_matrix = face.pre_transform(edge_from)
     else:
         #Place edge as is
         pretransform_matrix = np.eye(4)
     transform_matrix = np.dot(transform_2D, pretransform_matrix)
     #4D pts are the homogenous coordinates of the face i.e. [x,y,z,1]
     pretransformed_pts_4D = np.dot(pretransform_matrix, face.pts_4D)
     transfromed_pts_4D = np.dot(transform_matrix, face.pts_4D)
     pretransformed_pts_2D = pretransformed_pts_4D[0:2,:]
     #Numerical values for the coordinates are required for placement
     transfromed_pts_2D = eval_equation(transfromed_pts_4D[0:2, :])
     if not self.add_face(transfromed_pts_2D):
         #If face cannot be placed without collisions, attempt to reflect it
         reflection_matrix = np.array([[1,  0, 0, 0],
                                       [0, -1, 0, 0],
                                       [0,  0, 1, 0],
                                       [0,  0, 0, 1]])
         #Recompute pretransform and transform with rotation
         pretransform_matrix = np.dot(reflection_matrix, pretransform_matrix)
         transform_matrix = np.dot(transform_2D, pretransform_matrix)
         pretransformed_pts_4D = np.dot(pretransform_matrix, face.pts_4D)
         transfromed_pts_4D = np.dot(transform_matrix, face.pts_4D)
         pretransformed_pts_2D = pretransformed_pts_4D[0:2,:]
         transfromed_pts_2D = eval_equation(transfromed_pts_4D[0:2, :])
         if not self.add_face(transfromed_pts_2D) and not allow_overlap:
             #Face was not able to be placed connected to this edge
             #Keep track of face and hope it gets placed elsewhere
             #TODO: Try connecting along other edges or undoing previous placements?
             placed['overlapping'].append(face)
             return
     #Face is being placed
     placed['faces'].append(face)
     if face in placed['overlapping']:
         placed['overlapping'].remove(face)
     face.transform_2D = transform_matrix
     #Will this break if a face has to be flipped?
     ## find out how to transform the decoration. ##
     for e in face.get_2D_decorations():
             self.edges[e[0]] = DrawingEdge(e[0], [eval_equation(x) for x in e[1]],
                                     [eval_equation(x) for x in e[2]], EdgeType(e[3]))
     ## edges here is a dictionary, the key is decoration edge name. e is nested list and its first element is the edge name. ##
     #Place each edge
     for (i, edge) in enumerate(face.edges):
         #HACK: Do not place temporary edges
         if edge is None or edge.name[:4] == "temp":
             continue
         #Get the endpoints of the edge
         edge_pts_2D = (transfromed_pts_2D[:,i - 1],transfromed_pts_2D[:,i])
         if edge.name in placed['edges'].keys():
             edge_alias = placed['edges'][edge.name]
             if diff_edge(edge_alias, edge_pts_2D,2):
             #If the edge has already been placed in a different place, a cut must be made
             #Create a new edge
                 self.edges['temp' + edge.name] = DrawingEdge('temp' + edge.name, edge_pts_2D[0], edge_pts_2D[1], Cut())
             # Make old edge into a cut
                 self.edges[edge.name] = DrawingEdge(edge.name, edge_alias[0], edge_alias[1], Cut())
         else:
             #Add edge normally
             if len(edge.faces) == 1:
                 edge_type = Cut()
             else:
                 edge_type = Fold()
             self.edges[edge.name] = DrawingEdge(edge.name, edge_pts_2D[0], edge_pts_2D[1], edge_type)
             placed['edges'][edge.name] = edge_pts_2D
         if len(edge.faces) <= 1:
             # No other faces to be found, move on to next edge.
             continue
         if edge.is_tab():
             # Don't follow faces off of a Tab
             continue
         #Compute new transform matrix for next face
         rotation_matrix = rotate_x_to(pretransformed_pts_2D[:,i],pretransformed_pts_2D[:,i-1])
         origin_matrix = move_origin_to(pretransformed_pts_2D[:,i-1])
         next_transfrom_2D = np.dot(transform_2D,np.dot(origin_matrix,np.dot(rotation_matrix,np.eye(4))))
         #Place faces connected to edge
         for(f,a) in edge.faces.iteritems():
             self.place_faces(f, edge, next_transfrom_2D, placed)
     if check_for_overlap and len(placed['overlapping']):
         #Placement has finished, but some edges are still unplaced
         raise Exception('One or more faces could not be placed without overlap!')
Beispiel #5
0
def stl_write(faces, filename, thickness=0):
    """
    Writes a graph object represented by faces to an STL file.

    Args:
        faces (list): list of faces that compose the object.
        filename (str): filename to write STL to.
        thickness (int or float): thickness of each face to draw.

    """
    import triangle

    shape = None
    shells = []
    triangles = []
    for f in faces:
        r = f[0]
        # print ("the tramsform function is ",r)
        # if r is None:
        #     continue

        # if r is None: #No transform
        #     r = np.eye(4)
        A = f[1]

        facets = []
        B = triangle.triangulate(A, opts='p')
        if not 'triangles' in B:
            print "No triangles in " + f[2]
            continue

        if thickness:
            for t in [
                    np.transpose(
                        np.array([
                            list(B['vertices'][x]) + [0, 1]
                            for x in (face[0], face[1], face[2])
                        ])) for face in B['triangles']
            ]:
                facets.extend(
                    [np.dot(r, x) for x in inflate(t, thickness=thickness)])
            for t in [
                    np.transpose(
                        np.array([
                            list(A['vertices'][x]) + [0, 1]
                            for x in (edge[0], edge[1])
                        ])) for edge in A['segments']
            ]:
                facets.extend([
                    np.dot(r, x)
                    for x in inflate(t, thickness=thickness, edges=True)
                ])
        else:

            for t in [
                    np.transpose(
                        np.array([
                            list(B['vertices'][x]) + [0, 1]
                            for x in (face[0], face[1], face[2])
                        ])) for face in B['triangles']
            ]:
                #print "Here",r,t
                facets.append(np.dot(r, t))

        triangles.extend(facets)

        if thickness:
            FREECADPATH = '/usr/lib64/freecad/lib'
            import sys
            sys.path.append(FREECADPATH)
            import Part
            meshes = []
            for f in (np.transpose(t[0:3, :]) for t in facets):
                try:
                    meshes.append(
                        Part.Face(
                            Part.Wire([
                                Part.makeLine(tuple(f[x]), tuple(f[x - 1]))
                                for x in range(3)
                            ])))
                except RuntimeError:
                    print "Skipping face: " + repr(f)
            shell = Part.makeShell(meshes)
            shells.append(shell)
            if shape is None:
                shape = shell
            else:
                shape = shape.fuse(shell)

    if shape:
        with open("freecad" + filename, 'wb') as fp:
            shape.exportStl("freecad" + filename)

    from stlwriter import Binary_STL_Writer
    faces = triangles

    with open(filename, 'wb') as fp:
        writer = Binary_STL_Writer(fp)
        writer.add_faces(faces)
        writer.close()
Beispiel #6
0
 def get_3D_normal(self):
     if self.transform_3D is not None:
         o = np.dot(self.transform_3D, np.array([0, 0, 0, 1]))
         z = np.dot(self.transform_3D, np.array([0, 0, 1, 1]))
         return (z - o)[0:3, :]
Beispiel #7
0
 def get_3D_com(self):
     if self.transform_3D is not None:
         return np.dot(self.transform_3D, self.com_4D)[0:3, :]
Beispiel #8
0
 def get_3D_coords(self):
     if self.transform_3D is not None:
         return np.dot(self.transform_3D, self.pts_4D)[0:3, :]
Beispiel #9
0
 def get_2D_com(self):
     if self.transform_2D is not None:
         return np.dot(self.transform_2D, self.com_4D)[0:2, :]
Beispiel #10
0
 def get_2D_coords(self):
     if self.transform_2D is not None:
         return np.dot(self.transform_2D, self.pts_4D)[0:2, :]
Beispiel #11
0
    def place(self, edge_from, transform_2D, transform_3D, placed=None):
        if self.transform_2D is not None and self.transform_3D is not None and placed is not None and self in \
                placed['faces']:
            # TODO : verify that it connects appropriately along alternate path
            # print "Repeated face : " + self.name
            return

        if placed is None:  # Replacing the entire component
            placed = {'faces': []}  ## create a dictionary: placed, the key is 'faces'.

        ## Face is being placed into the list of key:'faces'. placed={'faces':[face1,face2,...,facen]} ##
        placed['faces'].append(self)

        if edge_from is not None:
            r = self.pre_transform(edge_from)
        else:
            r = np.eye(4)   ## create a identity unit matrix. ##

        self.transform_2D = np.dot(transform_2D, r)
        self.transform_3D = np.dot(transform_3D, r)

        pts_2D = np.dot(r, self.pts_4D)[0:2, :]  ##using numpy, 0-2 rows and all columns. ##

        coords_2D = self.get_2D_coords()
        coords_3D = self.get_3D_coords()

        for (i, e) in enumerate(self.edges):
            # XXX hack: don't follow small edges
            if e is None or e.is_tab():  ## do nothing to edges which is tabbed or without connection? ##
                continue

            el = self.edge_length(i)  ##return the length of edge by edge index i. ##
            try:
                if el <= 0.01:
                    continue
            except TypeError:
                # print 'sympyicized variable detected - ignoring edge length check'
                pass

            da = e.faces[self]  ## e is an edge? ##
            if da[1]:
                e.place((coords_2D[:, i - 1], coords_2D[:, i]), (coords_3D[:, i - 1], coords_3D[:, i]))
            else:
                e.place((coords_2D[:, i], coords_2D[:, i - 1]), (coords_3D[:, i], coords_3D[:, i - 1]))

            if len(e.faces) <= 1:  ## how !!!!! ##
                # No other faces to be found, move on to next edge.
                continue

            pt1 = pts_2D[:, i - 1]
            pt2 = pts_2D[:, i]

            # TODO : Only skip self and the face that you came from to verify multi-connected edges
            # XXX : Assumes both faces have opposite edge orientation
            #       Only works for non-hyper edges -- need to store edge orientation info for a +/- da
            for (f, a) in e.faces.iteritems():
                if a[1] ^ da[1]:
                    # opposite orientation
                    pta, ptb = pt1, pt2
                else:
                    # same orientation
                    pta, ptb = pt2, pt1

                x = rotate_x_to(ptb, pta)

                r2d = np.eye(4)
                r2d = np.dot(x, r2d)
                r2d = np.dot(move_origin_to(pta), r2d)

                r3d = rotate_x(np.deg2rad(a[0] + da[0]))
                r3d = np.dot(x, r3d)
                r3d = np.dot(move_origin_to(pta), r3d)

                f.place(e, np.dot(transform_2D, r2d), np.dot(transform_3D, r3d), placed=placed)
Beispiel #12
0
 def pre_transform(self, edge):
     index = self.edges.index(edge)
     # print edge
     # print self.edgeCoords(index)
     return np.dot(rotate_onto_x(*self.edge_coords(index)), move_to_origin(self.pts_2D[index]))