def __init__(self, cgal_elem, swoop_elem): from CGAL.CGAL_Kernel import \ Segment_2,\ Polygon_2,\ Point_2,\ Bbox_2,\ Iso_rectangle_2,\ do_intersect self.cgal_elem = cgal_elem self.swoop_elem = swoop_elem bbox = cgal_elem.bbox() self.rect = Rectangle.from_cgal_bbox(bbox, check=False) #do_intersect only works with iso_rectangle, not bbox self.iso_rect = Iso_rectangle_2(bbox.xmin(), bbox.ymin(), bbox.xmax(), bbox.ymax())
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 = map(lambda v: rotate_matrix.dot(v - center) + center, 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 xrange(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
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