Exemple #1
0
    def trim(self, trimPoly):
        if len(self.polygons) > 0 and len(trimPoly.polygons) > 0:

            polytrim = pyclipper.Pyclipper()  #Pyclipper
            polytrim.AddPaths(
                [[[int(self.scaling * p[0]),
                   int(self.scaling * p[1])] for p in pat]
                 for pat in trimPoly.polygons],
                poly_type=pyclipper.PT_CLIP,
                closed=True)
            polytrim.AddPaths(
                [[[int(self.scaling * p[0]),
                   int(self.scaling * p[1])] for p in pat]
                 for pat in self.polygons],
                poly_type=pyclipper.PT_SUBJECT,
                closed=True)
            try:
                trimmed = polytrim.Execute(pyclipper.CT_INTERSECTION,
                                           pyclipper.PFT_EVENODD,
                                           pyclipper.PFT_EVENODD)
                trimmed = pyclipper.SimplifyPolygons(trimmed)
                self.polygons = [[[
                    float(x[0]) / self.scaling,
                    float(x[1]) / self.scaling, self.zlevel
                ] for x in poly] for poly in trimmed]
            except:
                print("clipping intersection error")
Exemple #2
0
def clean_points(pts):
    """ Clean the polygon by getting rid of numerical artifacts. 
    This is required to overcome Gmsh parsing errors. """
    sc = constants.CLIPPER_SCALE
    spl_pts = pyclipper.SimplifyPolygons(pts)
    cln_pts = pyclipper.CleanPolygons(spl_pts)
    pts = sf(cln_pts, sc)
    return np.array(pts)
Exemple #3
0
    def offset(self, radius=0, rounding=0.0):
        offset = []
        clip = pyclipper.PyclipperOffset()  #Pyclipper
        polyclipper = pyclipper.Pyclipper()  #Pyclipper
        for pat in self.polygons:
            outPoly = [[int(self.scaling * p[0]),
                        int(self.scaling * p[1])] for p in pat]  #Pyclipper
            outPoly = pyclipper.SimplifyPolygons([outPoly])
            try:
                polyclipper.AddPaths(outPoly,
                                     poly_type=pyclipper.PT_SUBJECT,
                                     closed=True)
            except:
                None
                #print "path invalid",  outPoly
        poly = polyclipper.Execute(pyclipper.CT_UNION, pyclipper.PFT_EVENODD,
                                   pyclipper.PFT_EVENODD)
        clip.AddPaths(poly, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)

        offset = clip.Execute(-int((radius + rounding) * self.scaling))
        offset = pyclipper.SimplifyPolygons(offset)
        if rounding > 0.0:
            roundclipper = pyclipper.PyclipperOffset()
            roundclipper.AddPaths(offset, pyclipper.JT_ROUND,
                                  pyclipper.ET_CLOSEDPOLYGON)

            offset = roundclipper.Execute(int(rounding * self.scaling))
        offset = pyclipper.CleanPolygons(offset,
                                         distance=self.scaling *
                                         self.precision)
        #print (len(offset))

        result = PolygonGroup(scaling=self.scaling,
                              precision=self.precision,
                              zlevel=self.zlevel)
        result.polygons = []
        for poly in offset:
            if len(poly) > 0:
                output_poly = [[
                    float(x[0]) / self.scaling,
                    float(x[1]) / self.scaling, self.zlevel
                ] for x in poly]
                result.addPolygon(output_poly)
        return result
Exemple #4
0
def convertToClipper(pathArray, SCALE_FACTOR):
    clipperPaths = []
    for path in pathArray:
        points = []
        for edge in path:
            for pts in edge:  #points
                points.append([pts.x, pts.y])
        if len(points) > 0:
            scaled = pyclipper.scale_to_clipper(points, SCALE_FACTOR)
            clipperPaths.append(scaled)

    return pyclipper.SimplifyPolygons(clipperPaths)
Exemple #5
0
def bool_operation(subj, clip=None, method=None, closed=True):
    """ Angusj clipping library """

    from spira.gdsii.elemental.polygons import PolygonAbstract

    scale = 1

    pc = pyclipper.Pyclipper()

    if issubclass(type(subj), PolygonAbstract):
        subj = subj.polygons
    if issubclass(type(clip), PolygonAbstract):
        clip = clip.polygons

    if clip is not None:
        pc.AddPaths(st(clip, scale), pyclipper.PT_CLIP, True)
    pc.AddPaths(st(subj, scale), pyclipper.PT_SUBJECT, closed)

    subj = None
    if method == 'difference':
        subj = pc.Execute(pyclipper.CT_DIFFERENCE,
                          pyclipper.PFT_NONZERO,
                          pyclipper.PFT_NONZERO)
    elif method == 'union':
        subj = pc.Execute(pyclipper.CT_UNION,
                          pyclipper.PFT_NONZERO,
                          pyclipper.PFT_NONZERO)
    elif method == 'intersection':
        subj = pc.Execute(pyclipper.CT_INTERSECTION,
                          pyclipper.PFT_NONZERO,
                          pyclipper.PFT_NONZERO)
    elif method == 'exclusive':
        subj = pc.Execute(pyclipper.CT_XOR,
                          pyclipper.PFT_NONZERO,
                          pyclipper.PFT_NONZERO)
    else:
        raise ValueError('Please specify a clipping method')

    sp = pyclipper.SimplifyPolygons(subj)
#     cp = pyclipper.CleanPolygons(sf(sp, scale))
    return sp
Exemple #6
0
 def test_simplify_polygons(self):
     solution = pyclipper.SimplifyPolygons([PATH_SUBJ_1])
     solution_single = pyclipper.SimplifyPolygon(PATH_SUBJ_1)
     self.assertEqual(len(solution), 1)
     self.assertEqual(len(solution), len(solution_single))
     _do_solutions_match(solution, solution_single)
Exemple #7
0
    def getPolysAtSlice(self, objectToCut, plane, depth):
        fc = FreeCAD.ActiveDocument
        obj = fc.getObjectsByLabel(objectToCut)[0]
        shape = obj.Shape
        if hasattr(self.obj, "MaximumError") == False: error = .1
        else: error = self.obj.MaximumError.Value
        FreeCADGui.ActiveDocument.getObject(obj.Name).Deviation = error / 3.
        wires = list()
        for i in shape.slice(Base.Vector(0, 0, 1), self.zOff - depth):
            wires.append(i)
        polys = []
        for wire in wires:
            segList = []
            for edge in wire.OrderedEdges:
                segList.append(edge.discretize(QuasiDeflection=error / 3.))
            newWire = segList.pop()
            while len(segList) > 0:
                for seg in segList:
                    if self.dtp(seg[0], newWire[len(newWire) - 1]) < 0.00001:
                        newWire = newWire + seg[1:]
                        segList.remove(seg)
                        break
                    elif self.dtp(seg[len(seg) - 1],
                                  newWire[len(newWire) - 1]) < 0.00001:
                        temp = []
                        i = len(seg) - 2
                        while i >= 0:
                            temp.append(seg[i])
                            i = i - 1
                        newWire = newWire + temp
                        segList.remove(seg)
                        break
            poly = []
            for v in newWire:
                poly.append([v[0], v[1]])
            polys.append(poly)

        if hasattr(self, "lastSlice"):
            if self.lastSlice != None:
                scaledLastSlice = pyclipper.SimplifyPolygons(
                    self.scaleToClipper(self.lastSlice, 100000.))
                scaledPolys = pyclipper.SimplifyPolygons(
                    self.scaleToClipper(simplePolys, 100000.))
                pc = pyclipper.Pyclipper()
                pc.AddPath(scaledPolys, pyclipper.PT_CLIP, True)
                pc.AddPaths([scaledLastSlice], pyclipper.PT_SUBJECT, True)
                solution = pc.Execute(pyclipper.CT_UNION,
                                      pyclipper.PFT_EVENODD,
                                      pyclipper.PFT_EVENODD)
                simplePolys = self.scaleFromClipper(
                    pyclipper.SimplifyPolygons(solutions, 1 / 100000.))
            else:
                simplePolys = self.scaleFromClipper(
                    pyclipper.SimplifyPolygons(
                        self.scaleToClipper(polys, 100000.)), 1 / 100000.)
            return simplePolys
        else:
            return self.scaleFromClipper(
                pyclipper.SimplifyPolygons(self.scaleToClipper(polys,
                                                               100000.)),
                1 / 100000.)
Exemple #8
0
    def offsetPathOutIn(self, recursive=True):
        max_iterations = self.sliceIter.getValue()
        scaling = 1000.0
        output = []

        #define bounding box with tool radius and offset added
        radius = self.tool.getValue(
        ).diameter.value / 2.0 + self.radialOffset.value
        bound_min = [
            self.stockMinX.getValue() - radius,
            self.stockMinY.getValue() - radius
        ]
        bound_max = [
            self.stockMinX.getValue() + self.stockSizeX.getValue() + radius,
            self.stockMinY.getValue() + self.stockSizeY.getValue() + radius
        ]

        # sort patterns by slice levels
        patternLevels = dict()
        for p in self.patterns:
            patternLevels[p[0][2]] = []
        for p in self.patterns:
            patternLevels[p[0][2]].append(p)

        for sliceLevel in sorted(patternLevels.keys(), reverse=True):
            #define bounding box
            bb = [[bound_min[0], bound_min[1], sliceLevel],
                  [bound_min[0], bound_max[1], sliceLevel],
                  [bound_max[0], bound_max[1], sliceLevel],
                  [bound_max[0], bound_min[1], sliceLevel]]
            bbpoly = [[int(scaling * p[0]),
                       int(scaling * p[1])] for p in bb]  #Pyclipper

            print("Slice Level: ", sliceLevel)
            radius = self.tool.getValue(
            ).diameter.value / 2.0 + self.radialOffset.value
            iterations = max_iterations
            if iterations <= 0:
                iterations = 1

            input = patternLevels[sliceLevel]
            offsetOutput = []
            while len(input) > 0 and (iterations > 0):
                offset = []
                clip = pyclipper.PyclipperOffset()  #Pyclipper
                polyclipper = pyclipper.Pyclipper()  #Pyclipper
                for pat in input:
                    outPoly = [[int(scaling * p[0]),
                                int(scaling * p[1])] for p in pat]  #Pyclipper
                    outPoly = pyclipper.SimplifyPolygons([outPoly])

                    try:
                        polyclipper.AddPaths(outPoly,
                                             poly_type=pyclipper.PT_SUBJECT,
                                             closed=True)
                    except:
                        None
                        #print "path invalid",  outPoly
                poly = polyclipper.Execute(pyclipper.CT_UNION,
                                           pyclipper.PFT_EVENODD,
                                           pyclipper.PFT_EVENODD)
                clip.AddPaths(poly, pyclipper.JT_ROUND,
                              pyclipper.ET_CLOSEDPOLYGON)

                rounding = self.pathRounding.getValue()
                offset = clip.Execute(int((radius + rounding) * scaling))
                offset = pyclipper.SimplifyPolygons(offset)
                if rounding > 0.0:
                    roundclipper = pyclipper.PyclipperOffset()
                    roundclipper.AddPaths(offset, pyclipper.JT_ROUND,
                                          pyclipper.ET_CLOSEDPOLYGON)

                    offset = roundclipper.Execute(int(-rounding * scaling))
                offset = pyclipper.CleanPolygons(offset,
                                                 distance=scaling *
                                                 self.precision.getValue())

                # trim to outline
                polytrim = pyclipper.Pyclipper()  #Pyclipper
                polytrim.AddPath(bbpoly,
                                 poly_type=pyclipper.PT_CLIP,
                                 closed=True)
                polytrim.AddPaths(offset,
                                  poly_type=pyclipper.PT_SUBJECT,
                                  closed=True)
                try:
                    offset = polytrim.Execute(pyclipper.CT_INTERSECTION,
                                              pyclipper.PFT_EVENODD,
                                              pyclipper.PFT_EVENODD)
                except:
                    print("clipping intersection error")
                #print (len(offset))
                input = []
                for poly in offset:
                    offsetOutput.append(
                        [[x[0] / scaling, x[1] / scaling, sliceLevel]
                         for x in reversed(poly)])
                    if recursive:
                        input.append(
                            [[x[0] / scaling, x[1] / scaling, sliceLevel]
                             for x in poly])

                radius = self.sideStep.value
                iterations -= 1
            #self.patterns = input
            #offsetOutput.reverse()

            lastpoint = None

            for p in offsetOutput:
                closest_point_index = 0
                path_closed = True
                remainder_path = [
                ]  # append the start of a boundary path to the first boundary point to the end
                on_boundary = False
                opt_path = []
                for i in range(0, len(p)):
                    #check if point lies on boundary
                    bdist, bpoint, bindex = closest_point_on_polygon(p[i], bb)
                    if bdist < 0.001 and False:  # (TURNED OFF, buggy) point lies on boundary; skip this point
                        # if this is the first boundary point of the path, append the start to the end
                        if path_closed:
                            remainder_path = opt_path
                            remainder_path.append(p[i])
                            opt_path = []
                            path_closed = False
                        else:
                            if not on_boundary:  # if it is the first point on boundary, add it
                                #flush path up to here to output
                                opt_path.append(p[i])
                            if len(opt_path) > 0:
                                output.append(opt_path)
                                lastpoint = opt_path[-1]
                            opt_path = []
                        on_boundary = True
                    else:
                        if on_boundary and i > 0:
                            opt_path.append(p[i - 1])
                        on_boundary = False
                        opt_path.append(p[i])
                opt_path += remainder_path
                if lastpoint is not None and path_closed:
                    for i in range(0, len(p)):
                        # find closest point from last position
                        if dist(lastpoint, p[i]) < dist(
                                lastpoint, opt_path[closest_point_index]):
                            closest_point_index = i
                    opt_path = opt_path[
                        closest_point_index:] + opt_path[:closest_point_index]
                    # last point same as first point on closed paths (explicitly add it here)
                    opt_path.append(opt_path[0])
                if len(opt_path) > 0:
                    lastpoint = opt_path[-1]
                    output.append(opt_path)

        return output
Exemple #9
0
    def LoadGerberFile(self, evt):
        dlg = wx.FileDialog(self, "Open Gerber file", "", "",
                            "Gerber Files (*.gbl;*.gtl;*.gbr;*.cmp)|*.gbl;*.gtl;*.gbr;*.cmp|All Files (*.*)|*",
                            wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)

        if dlg.ShowModal() == wx.ID_CANCEL:
            self.SetStatusText("Load Gerber file cancelled by user", 0)
            return
        filename = dlg.GetPath()
        dlg.Destroy()

        self.SetStatusText("Loading Gerber: " + filename + "...", 0)

        [data, tracks] = load_file(filename)
        self.data = data

        xmin = 1E99
        xmax = -1E99
        ymin = 1E99
        ymax = -1E99

        sum1 = 0
        sumReg = 0
        sumBound = 0
        sumTracks = 0
        sumPads = 0

        cbounds = pyclipper.Pyclipper()
        boundarys = []
        pcb_edges = []

        layers = list(data.layers)
        for gl in layers:
            if gl.type == GerberLayer.TYPE_PCBEDGE:
                data.layers.remove(gl)
                pcb_edges.extend(gl.points)
                for segment in gl.points:
                    sum1 += len(segment)
                    for vertex in segment:
                        x = vertex[0]
                        y = vertex[1]
                        if x < xmin: xmin = x
                        if x > xmax: xmax = x
                        if y < ymin: ymin = y
                        if y > ymax: ymax = y
                continue
            if gl.type == GerberLayer.TYPE_REGION:
                sumReg += len(gl.points)
                # regions.extend(gl.points)
                continue
            if gl.type == GerberLayer.TYPE_TRACK:
                sumTracks += len(gl.points)
                continue
            if gl.type == GerberLayer.TYPE_PAD:
                sumPads += len(gl.points)
                continue
            if gl.type == GerberLayer.TYPE_BOUNDARY:
                # if gl.isDark:
                #     # boundarys.extend(gl.points)
                #     # if len(boundarys) == 0:
                #         boundarys.extend(gl.points)
                #     # else:
                #     #     cbounds.AddPaths(boundarys, pyclipper.PT_SUBJECT)
                #     #     cbounds.AddPaths(gl.points, pyclipper.PT_SUBJECT)
                #     #     boundarys = cbounds.Execute(pyclipper.CT_UNION, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD)
                #     #     cbounds.Clear()
                # else:
                #     cbounds.AddPaths(boundarys, pyclipper.PT_SUBJECT)
                #     cbounds.AddPaths(gl.points, pyclipper.PT_CLIP)
                #     boundarys = cbounds.Execute(pyclipper.CT_DIFFERENCE, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD)
                #     cbounds.Clear()
                if gl.isDark:
                    boundarys.extend(gl.points)
                else:
                    cbounds.AddPaths(boundarys, pyclipper.PT_SUBJECT)
                    cbounds.AddPaths(gl.points, pyclipper.PT_CLIP)
                    boundarys = cbounds.Execute(pyclipper.CT_DIFFERENCE, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
                    cbounds.Clear()
                sumBound += len(gl.points)
                for segment in gl.points:
                    sum1 += len(segment)
                    for vertex in segment:
                        x = vertex[0]
                        y = vertex[1]
                        if x < xmin: xmin = x
                        if x > xmax: xmax = x
                        if y < ymin: ymin = y
                        if y > ymax: ymax = y
                continue
            if gl.type == GerberLayer.TYPE_MERGEDCOPPER:
                data.layers.remove(gl)
                continue

        print "   fraction = ",self.data.fraction
        print "   found", sumBound, "polygons,", sum1, "vertices"
        print "   found", sumReg, "pours"
        print "   found", sumTracks, "tracks"
        print "   found", sumPads, "pads"
        print "   found", len(pcb_edges), "edge segments"
        print "   xmin: %0.3g " % xmin, "xmax: %0.3g " % xmax, "dx: %0.3g " % (xmax - xmin)
        print "   ymin: %0.3g " % ymin, "ymax: %0.3g " % ymax, "dy: %0.3g " % (ymax - ymin)

        data.xmin2 = xmin
        data.xmax2 = xmax
        data.ymin2 = ymin
        data.ymax2 = ymax

        if len(pcb_edges) == 0:
            outer_offset = (1 if data.units == 0 else 0.03937) * 10**data.fraction  # 1 mm
            # outer_offset = 0.01 * 10**data.fraction
            xmin -= outer_offset
            ymin -= outer_offset
            xmax += outer_offset
            ymax += outer_offset
            pcb_edge = [[xmax, ymax], [xmax, ymin], [xmin, ymin], [xmin, ymax], [xmax, ymax]]
            pcb_edges.append(pcb_edge)

        self.pcb_edges = pcb_edges
        self.boundarys = boundarys = pyclipper.SimplifyPolygons(boundarys, pyclipper.PFT_NONZERO)
        # boundarys = GerberReader3.replace_holes_with_seams(boundarys)
        GerberReader3.closeOffPolys(boundarys)

        data.layers.append(GerberLayer(True, "PCB Edge", pcb_edges, True, False, "blue", GerberLayer.TYPE_PCBEDGE))
        data.layers.append(GerberLayer(True, "Merged Copper", boundarys, False, color="brown", type=GerberLayer.TYPE_MERGEDCOPPER))

        # PCB bounds
        data.xmin = xmin
        data.xmax = xmax
        data.ymin = ymin
        data.ymax = ymax

        # View bounds
        # Includes the origin
        if xmin > 0: xmin = 0
        if xmax < 0: xmax = 0
        if ymin > 0: ymin = 0
        if ymax < 0: ymax = 0

        # Add margin
        ww = (xmax - xmin)*0.1
        hh = (ymax - ymin)*0.1
        xmin -= ww
        xmax += ww
        ymin -= hh
        ymax += hh

        self.contours = []
        self.layersPanel.loadLayersPanel(data, self.NotifyDataChange)
        self.canvas.loadData2(self.data, xmin, xmax, ymin, ymax)
        self.SetStatusText("Load Gerber file completed successfully", 0)
        self.origincombo.SetSelection(0)
        self.nativeLabel.SetLabelText("(File unit: %s, Dec. places: %0d)" % ("mm" if data.units == 0 else "in", data.fraction))