Example #1
0
def mergeLayers(src, dst, force=False):
    """
    Merge layers from the :class:`EagleFile` :code:`src` into :class:`EagleFile` :code:`dst`.  If there is some conflict
    between the two (different names for the same layer number or vice versa),
    then raise an exception (unless :code:`force == True`)

    :param src: The :class:`EagleFile` to update.
    :param dst:  The :class:`EagleFile` to draw layers from.
    :param force:  If :code:`True` overwrite the layers.  Otherwise, throw an :class:`SwoopError` on conflict.

    """
    for srcLayer in src.get_layers():
        for dstLayer in dst.get_layers():
            if ((srcLayer.name == dstLayer.name
                 and srcLayer.number != dstLayer.number)
                    or (srcLayer.name != dstLayer.name
                        and srcLayer.number == dstLayer.number)):
                if force:
                    try:
                        src.remove_layer(dstLayer)
                    except:
                        pass
                else:
                    raise Swoop.SwoopError("Layer mismatch: " +
                                           str(src.filename) + " <" +
                                           str(srcLayer.number) + ", '" +
                                           str(srcLayer.name) + "'>; " +
                                           str(dst.filename) + " = <" +
                                           str(dstLayer.number) + ", '" +
                                           str(dstLayer.name) + "'>;")
        if srcLayer.name not in dst.get_layersByName():
            dst.add_layer(srcLayer.clone())
Example #2
0
def propagatePartToBoard(part, brd):
    """
    Copy :code:`part` to ``brd`` by creating a new :class:`Element` and populating it accordingly.
    If the part already exists, it will be replaced.  Attributes are not displayed by default, but the display layer is set to "Document".
    
    If the library for the part is missing in the board, it will be create.  If the package is missing, it will be copied.  If it exists and the package for the part and the package in the board are not the same, raise an exception.

    .. Note::
       This function doesn't update the board's signals.  You can run :meth:`rebuildBoardConnections` to do that.

    :param part: :class:`Part` object that to propagate.
    :param brd: Destination :class`BoardFile`.
    :rtype: :code:`None`

    """
    if part.find_device().get_package() is None:
        return

    if part.find_package() is None:
        raise Swoop.SwoopError(
            "Can't find package for '{}' ({}.{}.{}.{}).".format(
                part.get_name(), part.get_library(), part.get_deviceset(),
                part.get_device(), part.get_technology()))

    dst_lib = brd.get_library(part.get_library())

    if dst_lib is None:
        dst_lib = Swoop.Library().set_name(part.get_library())
        brd.add_library(dst_lib)

    #src_lib = part.find_library()
    #assert src_lib is not None, "Missing library '{}' for part '{}'".format(part.get_library(), part.get_name())

    dst_package = dst_lib.get_package(part.find_package().get_name())
    if dst_package is None:
        dst_package = part.find_package().clone()
        dst_lib.add_package(dst_package)
    else:
        assert dst_package.is_equal(part.find_package(
        )), "Package from schematic is not the same as package in board"

    # Reverse-engineered logic about setting values in board files.
    if part.find_deviceset().get_uservalue():
        fallback_value = ""
    else:
        fallback_value = part.get_deviceset() + part.get_device()

    n = (Swoop.Element().set_name(part.get_name()).set_library(
        part.get_library()).set_package(
            part.find_package().get_name()).set_value(part.get_value(
            ) if part.get_value() is not None else fallback_value).set_x(
                0).set_y(0))

    for a in part.find_technology().get_attributes():
        n.add_attribute(a.clone().set_display("off").set_layer("Document"))

    for a in part.get_attributes():
        n.add_attribute(a.clone().set_display("off").set_layer("Document"))

    brd.add_element(n)
Example #3
0
    def _layer_matches(self, query, layer_name):
        if query is None:
            return True

        if isinstance(query, str):
            return query == layer_name
        elif isinstance(query, int):
            return query == self.get_file().layer_name_to_number(layer_name)
        elif isinstance(query, Swoop.Layer):
            return query == query.get_name()
        elif isinstance(query, list):
            return layer_name in query
        elif hasattr(query, '__call__'):
            return query(layer_name)
        else:
            raise Swoop.SwoopError("illegal layer query: {}".format(query))
Example #4
0
    def _do_polygonize_wires(self, wires, layer_query, **options):
        """
        Try to deal with lines enclose areas.
        """
        if "polygonize_wires" in options:
            mode = options["polygonize_wires"]
        else:
            mode = ShapelyEagleFilePart.POLYGONIZE_NONE

        #log.debug("_do_polygonize_wires {} {} {}".format(mode, wires, layer_query))
        if mode == ShapelyEagleFilePart.POLYGONIZE_NONE:
            return shapely.ops.unary_union(
                wires.get_geometry(layer_query=layer_query, **options))
        else:
            widths = wires.get_width().unique()
            result = shapes.LineString()

            for w in widths:
                o = copy.copy(options)
                o["apply_width"] = False
                geometry = wires.with_width(w).get_geometry(
                    layer_query=layer_query, **o)
                polygons, dangles, cuts, invalids = shapely.ops.polygonize_full(
                    list(geometry))
                if mode == ShapelyEagleFilePart.POLYGONIZE_STRICT:
                    if len(dangles) + len(cuts) + len(invalids) > 0:
                        raise SwoopError(
                            "Tried to polygonize non-polygon ({})".format(
                                self))

                combined = shapely.ops.unary_union(
                    [polygons, dangles, cuts, invalids])
                combined = self._apply_width(combined, width=w, **options)

                result = result.union(combined)

        if mode != ShapelyEagleFilePart.POLYGONIZE_STRICT and mode != ShapelyEagleFilePart.POLYGONIZE_BEST_EFFORT:
            raise Swoop.SwoopError("Unknown polygonize mode: {}".mode)

        return result
Example #5
0
    def render_pad(self, layer_query, drill, **options):

        DRU = self.get_DRU()
        if self._layer_matches(layer_query, "Holes"):
            hole = shapes.Point(self.get_x(), self.get_y()).buffer(drill / 2)
            return hole

        radius = (drill / 2)
        radius = radius + scaleAndBound(radius, DRU.rvPadTop, DRU.rlMinPadTop,
                                        DRU.rlMaxPadTop)

        if layer_query is not None and self.get_file().get_layer(
                layer_query).get_number() > 16 and not self._layer_matches(
                    layer_query, "tStop") and not self._layer_matches(
                        layer_query, "bStop"):
            return shapes.LineString()

        if self.get_shape() == "square":
            shape = shapes.box(self.get_x() - radius,
                               self.get_y() - radius,
                               self.get_x() + radius,
                               self.get_y() + radius)
        elif self.get_shape() == "round" or self.get_shape() is None:
            shape = shapes.point.Point(self.get_x(),
                                       self.get_y()).buffer(radius)
        elif self.get_shape() == "octagon":
            shape = shapes.box(self.get_x() - radius,
                               self.get_y() - radius,
                               self.get_x() + radius,
                               self.get_y() + radius)
            shape = shape.intersection(affinity.rotate(shape, 45))
        elif self.get_shape() == "long":
            shape = shapely.ops.unary_union([
                shapes.point.Point(
                    self.get_x() + DRU.psElongationLong / 100.0 * radius,
                    self.get_y()).buffer(radius),
                shapes.point.Point(
                    self.get_x() - DRU.psElongationLong / 100.0 * radius,
                    self.get_y()).buffer(radius),
                shapes.box(
                    self.get_x() - DRU.psElongationLong / 100.0 * radius,
                    self.get_y() - radius,
                    self.get_x() + DRU.psElongationLong / 100.0 * radius,
                    self.get_y() + radius)
            ])
        elif self.get_shape() == "offset":
            shape = shapely.ops.unary_union([
                shapes.point.Point(
                    self.get_x() + DRU.psElongationOffset / 100.0 * radius * 2,
                    self.get_y()).buffer(radius),
                shapes.point.Point(self.get_x(), self.get_y()).buffer(radius),
                shapes.box(
                    self.get_x(),
                    self.get_y() - radius,
                    self.get_x() + DRU.psElongationLong / 100.0 * radius * 2,
                    self.get_y() + radius)
            ])
        else:
            raise Swoop.SwoopError("Unknown pad shape: '{}'".format(
                self.get_shape()))

        if shape is not None:
            if self._layer_matches(layer_query,
                                   "tStop") or self._layer_matches(
                                       layer_query, "bStop"):
                shape = shape.buffer(computeStopMaskExtra(radius, DRU))

        if options and "fail_on_missing" in options and options[
                "fail_on_missing"] and shape is None:
            raise NotImplemented(
                "Geometry for pad shape '{}' is not implemented yet.".format(
                    self.get_shape()))
        elif shape is None:
            shape = shapes.LineString()

        return shape