From d90da4000f3fd542da1896e705d3db43fd48ea4b Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Thu, 16 Oct 2014 18:13:43 -0400 Subject: Add primitive definitions and bounding box calcs for DRC --- gerber/primitives.py | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 gerber/primitives.py (limited to 'gerber/primitives.py') diff --git a/gerber/primitives.py b/gerber/primitives.py new file mode 100644 index 0000000..366c397 --- /dev/null +++ b/gerber/primitives.py @@ -0,0 +1,193 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# copyright 2014 Hamilton Kibbe + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import math +from operator import sub + + +class Primitive(object): + def bounding_box(self): + """ Calculate bounding box + + will be helpful for sweep & prune during DRC clearance checks. + + Return ((min x, max x), (min y, max y)) + """ + pass + + +class Line(Primitive): + """ + """ + def __init__(self, start, end, width): + self.start = start + self.end = end + self.width = width + + @property + def angle(self): + dx, dy = tuple(map(sub, end, start)) + angle = degrees(math.tan(dy/dx)) + + def bounding_box(self): + width_2 = self.width / 2. + min_x = min(self.start[0], self.end[0]) - width_2 + max_x = max(self.start[0], self.end[0]) + width_2 + min_y = min(self.start[1], self.end[1]) - width_2 + max_y = max(self.start[1], self.end[1]) + width_2 + return ((min_x, max_x), (min_y, max_y)) + + +class Arc(Primitive): + """ + """ + def __init__(self, start, end, center, direction, width): + self.start = start + self.end = end + self.center = center + self.direction = direction + self.width = width + + @property + def start_angle(self): + dy, dx = map(sub, self.start, self.center) + return math.atan2(dy, dx) + + @property + def end_angle(self): + dy, dx = map(sub, self.end, self.center) + return math.atan2(dy, dx) + + def bounding_box(self): + pass + +class Circle(Primitive): + """ + """ + def __init__(self, position, diameter): + self.position = position + self.diameter = diameter + self.radius = diameter / 2. + + def bounding_box(self): + min_x = self.position[0] - self.radius + max_x = self.position[0] + self.radius + min_y = self.position[1] - self.radius + max_y = self.position[1] + self.radius + return ((min_x, max_x), (min_y, max_y)) + + +class Rectangle(Primitive): + """ + """ + def __init__(self, position, width, height): + self.position = position + self.width = width + self.height = height + + @property + def lower_left(self): + return (self.position[0] - (self.width / 2.), + self.position[1] - (self.height / 2.)) + + @property + def upper_right(self): + return (self.position[0] + (self.width / 2.), + self.position[1] + (self.height / 2.)) + + def bounding_box(self): + min_x = self.lower_left[0] + max_x = self.upper_right[0] + min_y = self.lower_left[1] + max_y = self.upper_right[1] + return ((min_x, max_x), (min_y, max_y)) + + +class Obround(Primitive): + """ + """ + def __init__(self, position, width, height) + self.position = position + self.width = width + self.height = height + + @property + def orientation(self): + return 'vertical' if self.height > self.width else 'horizontal' + + @property + def lower_left(self): + return (self.position[0] - (self.width / 2.), + self.position[1] - (self.height / 2.)) + + @property + def upper_right(self): + return (self.position[0] + (self.width / 2.), + self.position[1] + (self.height / 2.)) + + def bounding_box(self): + min_x = self.lower_left[0] + max_x = self.upper_right[0] + min_y = self.lower_left[1] + max_y = self.upper_right[1] + return ((min_x, max_x), (min_y, max_y)) + + +class Polygon(Primitive): + """ + """ + def __init__(self, position, sides, radius): + self.position = position + self.sides = sides + self.radius = radius + + def bounding_box(self): + min_x = self.position[0] - self.radius + max_x = self.position[0] + self.radius + min_y = self.position[1] - self.radius + max_y = self.position[1] + self.radius + return ((min_x, max_x), (min_y, max_y)) + + +class Region(Primitive): + """ + """ + def __init__(self, points): + self.points = points + + def bounding_box(self): + x_list, y_list = zip(*self.points) + min_x = min(x_list) + max_x = max(x_list) + min_y = min(y_list) + max_y = max(y_list) + return ((min_x, max_x), (min_y, max_y)) + + +class Drill(Primitive): + """ + """ + def __init__(self, position, diameter): + self.position = position + self.diameter = diameter + self.radius = diameter / 2. + + def bounding_box(self): + min_x = self.position[0] - self.radius + max_x = self.position[0] + self.radius + min_y = self.position[1] - self.radius + max_y = self.position[1] + self.radius + return ((min_x, max_x), (min_y, max_y)) -- cgit From 6d2db67e6d0973ce26ce3a6700ca44295f73fea7 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Sat, 18 Oct 2014 01:44:51 -0400 Subject: Refactor rendering --- gerber/primitives.py | 67 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 16 deletions(-) (limited to 'gerber/primitives.py') diff --git a/gerber/primitives.py b/gerber/primitives.py index 366c397..670b758 100644 --- a/gerber/primitives.py +++ b/gerber/primitives.py @@ -19,11 +19,15 @@ from operator import sub class Primitive(object): + + def __init__(self, level_polarity='dark'): + self.level_polarity = level_polarity + def bounding_box(self): """ Calculate bounding box will be helpful for sweep & prune during DRC clearance checks. - + Return ((min x, max x), (min y, max y)) """ pass @@ -32,16 +36,19 @@ class Primitive(object): class Line(Primitive): """ """ - def __init__(self, start, end, width): + def __init__(self, start, end, width, level_polarity='dark'): + super(Line, self).__init__(level_polarity) self.start = start self.end = end self.width = width - + @property def angle(self): - dx, dy = tuple(map(sub, end, start)) - angle = degrees(math.tan(dy/dx)) + delta_x, delta_y = tuple(map(sub, end, start)) + angle = degrees(math.tan(delta_y/delta_x)) + return angle + @property def bounding_box(self): width_2 = self.width / 2. min_x = min(self.start[0], self.end[0]) - width_2 @@ -54,7 +61,8 @@ class Line(Primitive): class Arc(Primitive): """ """ - def __init__(self, start, end, center, direction, width): + def __init__(self, start, end, center, direction, width, level_polarity='dark'): + super(Arc, self).__init__(level_polarity) self.start = start self.end = end self.center = center @@ -71,17 +79,23 @@ class Arc(Primitive): dy, dx = map(sub, self.end, self.center) return math.atan2(dy, dx) + @property def bounding_box(self): pass class Circle(Primitive): """ """ - def __init__(self, position, diameter): + def __init__(self, position, diameter, level_polarity='dark'): + super(Circle, self).__init__(level_polarity) self.position = position self.diameter = diameter - self.radius = diameter / 2. + @property + def radius(self): + return self.diameter / 2. + + @property def bounding_box(self): min_x = self.position[0] - self.radius max_x = self.position[0] + self.radius @@ -89,11 +103,16 @@ class Circle(Primitive): max_y = self.position[1] + self.radius return ((min_x, max_x), (min_y, max_y)) + @property + def stroke_width(self): + return self.diameter + class Rectangle(Primitive): """ """ - def __init__(self, position, width, height): + def __init__(self, position, width, height, level_polarity='dark'): + super(Rectangle, self).__init__(level_polarity) self.position = position self.width = width self.height = height @@ -108,6 +127,7 @@ class Rectangle(Primitive): return (self.position[0] + (self.width / 2.), self.position[1] + (self.height / 2.)) + @property def bounding_box(self): min_x = self.lower_left[0] max_x = self.upper_right[0] @@ -115,11 +135,16 @@ class Rectangle(Primitive): max_y = self.upper_right[1] return ((min_x, max_x), (min_y, max_y)) + @property + def stroke_width(self): + return max((self.width, self.height)) + class Obround(Primitive): """ """ - def __init__(self, position, width, height) + def __init__(self, position, width, height, level_polarity='dark'): + super(Obround, self).__init__(level_polarity) self.position = position self.width = width self.height = height @@ -138,6 +163,7 @@ class Obround(Primitive): return (self.position[0] + (self.width / 2.), self.position[1] + (self.height / 2.)) + @property def bounding_box(self): min_x = self.lower_left[0] max_x = self.upper_right[0] @@ -149,11 +175,13 @@ class Obround(Primitive): class Polygon(Primitive): """ """ - def __init__(self, position, sides, radius): + def __init__(self, position, sides, radius, level_polarity='dark'): + super(Polygon, self).__init__(level_polarity) self.position = position self.sides = sides self.radius = radius - + + @property def bounding_box(self): min_x = self.position[0] - self.radius max_x = self.position[0] + self.radius @@ -165,9 +193,11 @@ class Polygon(Primitive): class Region(Primitive): """ """ - def __init__(self, points): + def __init__(self, points, level_polarity='dark'): + super(Region, self).__init__(level_polarity) self.points = points - + + @property def bounding_box(self): x_list, y_list = zip(*self.points) min_x = min(x_list) @@ -181,10 +211,15 @@ class Drill(Primitive): """ """ def __init__(self, position, diameter): + super(Drill, self).__init__('dark') self.position = position self.diameter = diameter - self.radius = diameter / 2. - + + @property + def radius(self): + return self.diameter / 2. + + @property def bounding_box(self): min_x = self.position[0] - self.radius max_x = self.position[0] + self.radius -- cgit