Exemplo n.º 1
0
    def _get_cgal_elem(self):
        """
        Get a cgal geometry element representing this object, if any
        Width is only considered for Wire
        """
        from CGAL.CGAL_Kernel import \
            Segment_2,\
            Polygon_2,\
            Point_2,\
            Bbox_2,\
            Iso_rectangle_2,\
            do_intersect

        if isinstance(self, Swoop.Rectangle):
            rect = Rectangle(self.get_point(0), self.get_point(1), check=False)
            verts = list(rect.vertices_ccw())
            if self.get_rot() is not None:
                angle_obj = angle_match(self.get_rot())
                angle = math.radians(angle_obj['angle'])
                if angle_obj['mirrored']:
                    angle *= -1
                origin = rect.center()
                rmat = Rectangle.rotation_matrix(angle)
                for i, v in enumerate(verts):
                    verts[i] = np.dot(v - origin, rmat) + origin
            return Polygon_2(list(map(np2cgal, verts)))

        elif isinstance(self, Swoop.Wire):
            p1 = self.get_point(0)
            p2 = self.get_point(1)
            if self.get_width() is None or self.get_width() == 0:
                return Segment_2(np2cgal(p1), np2cgal(p2))
            else:
                # Wire has width
                # This is important to consider because wires can represent traces
                # When doing a query, it is important we can pick up the trace
                if p1[0] > p2[0]:
                    p1, p2 = p2, p1  # p1 is the left endpoint
                elif p1[0] == p2[0] and p1[1] > p2[1]:
                    p1, p2 = p2, p1  # or the bottom

                vec = (p2 - p1)
                vec /= np.linalg.norm(vec)  # Normalize
                radius = np.array(vec[1], -vec[0])
                radius *= self.get_width(
                ) / 2.0  # "Radius" of the wire, perpendicular to it

                vertices = []
                # Go around the vertices of the wire in CCW order
                # This should give you a rotated rectangle
                vertices.append(np2cgal(p1 + radius))
                vertices.append(np2cgal(p2 + radius))
                vertices.append(np2cgal(p2 - radius))
                vertices.append(np2cgal(p1 - radius))
                return Polygon_2(vertices)
        elif isinstance(self, Swoop.Polygon):
            return Polygon_2(
                [np2cgal(v.get_point()) for v in self.get_vertices()])
        else:
            return None
Exemplo n.º 2
0
    def get_bounding_box(self, layer=None, type=None):
        """
        Get the minimum bounding box enclosing this list of primitive elements
        More accurate than self._get_cgal_elem().bbox(), because it accounts for segment width

        :param layer: Swoop layer to filter on
        """
        def max_min(vertex_list, width=None):
            max = np.maximum.reduce(vertex_list)
            min = np.minimum.reduce(vertex_list)
            if width is not None:
                radius = np.array([width, width]) / 2.0
                max += radius
                min -= radius
            return max, min

        if isinstance(self, Swoop.Polygon):
            vertices = [v.get_point() for v in self.get_vertices()]
            return Rectangle(*max_min(vertices, self.get_width()))
        elif isinstance(self, Swoop.Wire):
            if self.get_curve() is not None:
                theta = math.radians(self.get_curve())  # angle swept by arc
                theta = math.fmod(theta, 2 * math.pi)
                p1 = self.get_point(0)  # 2 points on the circle
                p2 = self.get_point(1)
                return arc_bounding_box(p1, p2,
                                        theta).pad(self.get_width() / 2.0)
            else:
                vertices = [self.get_point(0), self.get_point(1)]
                return Rectangle(*max_min(vertices, self.get_width()),
                                 check=False)
        elif isinstance(self, Swoop.Rectangle):
            #get_cgal_elem already handles rotation
            bbox = self._get_cgal_elem().bbox()
            return Rectangle.from_cgal_bbox(bbox, check=False)
        elif isinstance(self, Swoop.Via) or isinstance(self, Swoop.Pad):
            #These assume default settings
            #Unfortunately, restring can change the sizes of things after import

            center = self.get_point()
            if self.get_diameter() is None:
                # Gotta figure it out from drill
                if self.get_drill() < 1.0:
                    diameter = self.get_drill() + 0.5
                else:
                    diameter = self.get_drill() * 1.5
            else:
                diameter = self.get_diameter()
            radius = diameter / 2.0 * np.ones(2)

            angle = 0.0
            if isinstance(self, Swoop.Pad) and self.get_rot() is not None:
                angle_m = angle_match(self.get_rot())
                angle = angle_m['angle']
                if angle_m['mirrored']:
                    angle = 180.0 - angle
            rotate_matrix = Rectangle.rotation_matrix(math.radians(angle))

            if self.get_shape() in ['long', 'offset']:
                # This is basically a square pad with 180º arc endcaps
                if self.get_shape() == 'offset':
                    center[
                        0] += diameter / 2.0  # Center is offset to the left, correct it
                rect = Rectangle(center - radius, center + radius)
                verts = list(rect.vertices())
                verts = [rotate_matrix.dot(v - center) + center for v in verts]
                left_cap = arc_bounding_box(verts[0], verts[3], pi)
                right_cap = arc_bounding_box(verts[2], verts[1], pi)

                rect = Rectangle.union(rect, left_cap)
                rect = Rectangle.union(rect, right_cap)
                return rect
            elif self.get_shape() == 'octagon':
                vertex = np.array(
                    [diameter / 2.0, diameter / 2.0 * math.tan(2 * pi / 16)])
                vertex = rotate_matrix.dot(vertex)
                vertices = []
                rot = Rectangle.rotation_matrix(2 * pi / 8)
                for i in range(8):
                    vertices.append(vertex.copy() + center)
                    vertex = rot.dot(vertex)
                return Rectangle.from_vertices(vertices, check=True)
            else:
                rect = Rectangle(center - radius, center + radius)
                if self.get_shape() == 'square':
                    rect.rotate_resize(angle, origin=center)
                return rect
        elif isinstance(self, Swoop.Smd):
            center = self.get_point()
            radius = np.array([self.get_dx(), self.get_dy()]) / 2.0
            if self.get_rot() is not None:
                angle = angle_match(self.get_rot())
                radius = abs(
                    Rectangle.rotation_matrix(math.radians(
                        angle['angle'])).dot(radius))
            return Rectangle(center - radius, center + radius)
        elif isinstance(self, Swoop.Circle):
            center = self.get_point()
            radius = np.ones(2) * (self.get_radius() + self.get_width() / 2.0)
            return Rectangle(center - radius, center + radius)
        elif isinstance(self, Swoop.Hole):
            center = self.get_point()
            radius = np.ones(2) * self.get_drill() / 2.0
            return Rectangle(center - radius, center + radius)
        elif isinstance(self, Swoop.Element):
            # Element objects do not have enough information for the bounding box
            # That gets set in the constructor
            if hasattr(self, "_extension_geo_elem"):
                return self._extension_geo_elem.rect
            else:
                tform = self.get_transform()
                bbox = self.find_package().get_bounding_box(layer=layer,
                                                            type=type)
                if bbox is None:
                    return None
                return tform.apply(bbox)
        elif isinstance(self, Swoop.Package):
            rect = None
            for c in self.get_children():
                if ((layer is None) or (hasattr(c,"get_layer") and c.get_layer()==layer))\
                        and ((type is None) or isinstance(c, type)):
                    r = c.get_bounding_box()
                    if r is not None:
                        if rect is None:
                            rect = r
                        rect = Rectangle.union(rect, r)
            return rect
        else:
            return None