First time any macro renders
This commit is contained in:
parent
ca3c682da5
commit
4a815bf25d
5 changed files with 125 additions and 0 deletions
|
|
@ -16,7 +16,9 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from math import pi
|
||||
from .utils import validate_coordinates, inch, metric
|
||||
from .primitives import Circle, Line, Rectangle
|
||||
|
||||
|
||||
# TODO: Add support for aperture macro variables
|
||||
|
|
@ -67,6 +69,12 @@ class AMPrimitive(object):
|
|||
|
||||
def to_metric(self):
|
||||
raise NotImplementedError('Subclass must implement `to-metric`')
|
||||
|
||||
def to_primitive(self, units):
|
||||
"""
|
||||
Convert to a primitive, as defines the primitives module (for drawing)
|
||||
"""
|
||||
raise NotImplementedError('Subclass must implement `to-primitive`')
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__dict__ == other.__dict__
|
||||
|
|
@ -120,6 +128,12 @@ class AMCommentPrimitive(AMPrimitive):
|
|||
def to_gerber(self, settings=None):
|
||||
return '0 %s *' % self.comment
|
||||
|
||||
def to_primitive(self, units):
|
||||
"""
|
||||
Returns None - has not primitive representation
|
||||
"""
|
||||
return None
|
||||
|
||||
def __str__(self):
|
||||
return '<Aperture Macro Comment: %s>' % self.comment
|
||||
|
||||
|
|
@ -189,6 +203,9 @@ class AMCirclePrimitive(AMPrimitive):
|
|||
y = self.position[1])
|
||||
return '{code},{exposure},{diameter},{x},{y}*'.format(**data)
|
||||
|
||||
def to_primitive(self, units):
|
||||
return Circle((self.position), self.diameter, units=units)
|
||||
|
||||
|
||||
class AMVectorLinePrimitive(AMPrimitive):
|
||||
""" Aperture Macro Vector Line primitive. Code 2 or 20.
|
||||
|
|
@ -273,6 +290,9 @@ class AMVectorLinePrimitive(AMPrimitive):
|
|||
endy = self.end[1],
|
||||
rotation = self.rotation)
|
||||
return fmtstr.format(**data)
|
||||
|
||||
def to_primitive(self, units):
|
||||
return Line(self.start, self.end, Rectangle(None, self.width, self.width), units=units)
|
||||
|
||||
|
||||
class AMOutlinePrimitive(AMPrimitive):
|
||||
|
|
@ -360,6 +380,9 @@ class AMOutlinePrimitive(AMPrimitive):
|
|||
rotation=str(self.rotation)
|
||||
)
|
||||
return "{code},{exposure},{n_points},{start_point},{points},{rotation}*".format(**data)
|
||||
|
||||
def to_primitive(self, units):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class AMPolygonPrimitive(AMPrimitive):
|
||||
|
|
@ -450,6 +473,9 @@ class AMPolygonPrimitive(AMPrimitive):
|
|||
)
|
||||
fmt = "{code},{exposure},{vertices},{position},{diameter},{rotation}*"
|
||||
return fmt.format(**data)
|
||||
|
||||
def to_primitive(self, units):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class AMMoirePrimitive(AMPrimitive):
|
||||
|
|
@ -562,6 +588,9 @@ class AMMoirePrimitive(AMPrimitive):
|
|||
fmt = "{code},{position},{diameter},{ring_thickness},{gap},{max_rings},{crosshair_thickness},{crosshair_length},{rotation}*"
|
||||
return fmt.format(**data)
|
||||
|
||||
def to_primitive(self, units):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class AMThermalPrimitive(AMPrimitive):
|
||||
""" Aperture Macro Thermal primitive. Code 7.
|
||||
|
|
@ -646,6 +675,9 @@ class AMThermalPrimitive(AMPrimitive):
|
|||
fmt = "{code},{position},{outer_diameter},{inner_diameter},{gap}*"
|
||||
return fmt.format(**data)
|
||||
|
||||
def to_primitive(self, units):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class AMCenterLinePrimitive(AMPrimitive):
|
||||
""" Aperture Macro Center Line primitive. Code 21.
|
||||
|
|
@ -729,6 +761,9 @@ class AMCenterLinePrimitive(AMPrimitive):
|
|||
fmt = "{code},{exposure},{width},{height},{center},{rotation}*"
|
||||
return fmt.format(**data)
|
||||
|
||||
def to_primitive(self, units):
|
||||
return Rectangle(self.center, self.width, self.height, rotation=self.rotation * pi / 180.0, units=units)
|
||||
|
||||
|
||||
class AMLowerLeftLinePrimitive(AMPrimitive):
|
||||
""" Aperture Macro Lower Left Line primitive. Code 22.
|
||||
|
|
@ -811,6 +846,9 @@ class AMLowerLeftLinePrimitive(AMPrimitive):
|
|||
fmt = "{code},{exposure},{width},{height},{lower_left},{rotation}*"
|
||||
return fmt.format(**data)
|
||||
|
||||
def to_primitive(self, units):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class AMUnsupportPrimitive(AMPrimitive):
|
||||
@classmethod
|
||||
|
|
@ -829,3 +867,6 @@ class AMUnsupportPrimitive(AMPrimitive):
|
|||
|
||||
def to_gerber(self, settings=None):
|
||||
return self.primitive
|
||||
|
||||
def to_primitive(self, units):
|
||||
return None
|
||||
|
|
@ -26,6 +26,7 @@ from .utils import (parse_gerber_value, write_gerber_value, decimal_string,
|
|||
from .am_statements import *
|
||||
from .am_read import read_macro
|
||||
from .am_eval import eval_macro
|
||||
from .primitives import AMGroup
|
||||
|
||||
|
||||
class Statement(object):
|
||||
|
|
@ -388,6 +389,8 @@ class AMParamStmt(ParamStmt):
|
|||
self.primitives.append(AMThermalPrimitive.from_gerber(primitive))
|
||||
else:
|
||||
self.primitives.append(AMUnsupportPrimitive.from_gerber(primitive))
|
||||
|
||||
return AMGroup(self.primitives, units=self.units)
|
||||
|
||||
def to_inch(self):
|
||||
if self.units == 'metric':
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import math
|
|||
from operator import add, sub
|
||||
|
||||
from .utils import validate_coordinates, inch, metric
|
||||
from jsonpickle.util import PRIMITIVES
|
||||
|
||||
|
||||
class Primitive(object):
|
||||
|
|
@ -425,6 +426,10 @@ class Ellipse(Primitive):
|
|||
|
||||
class Rectangle(Primitive):
|
||||
"""
|
||||
When rotated, the rotation is about the center point.
|
||||
|
||||
Only aperture macro generated Rectangle objects can be rotated. If you aren't in a AMGroup,
|
||||
then you don't need to worry about rotation
|
||||
"""
|
||||
def __init__(self, position, width, height, **kwargs):
|
||||
super(Rectangle, self).__init__(**kwargs)
|
||||
|
|
@ -702,6 +707,57 @@ class Polygon(Primitive):
|
|||
def offset(self, x_offset=0, y_offset=0):
|
||||
self.position = tuple(map(add, self.position, (x_offset, y_offset)))
|
||||
|
||||
class AMGroup(Primitive):
|
||||
"""
|
||||
"""
|
||||
def __init__(self, amprimitives, **kwargs):
|
||||
super(AMGroup, self).__init__(**kwargs)
|
||||
|
||||
self.primitives = []
|
||||
for amprim in amprimitives:
|
||||
prim = amprim.to_primitive(self.units)
|
||||
if prim:
|
||||
self.primitives.append(prim)
|
||||
self._position = None
|
||||
self._to_convert = ['arimitives']
|
||||
|
||||
@property
|
||||
def flashed(self):
|
||||
return True
|
||||
|
||||
@property
|
||||
def bounding_box(self):
|
||||
xlims, ylims = zip(*[p.bounding_box for p in self.primitives])
|
||||
minx, maxx = zip(*xlims)
|
||||
miny, maxy = zip(*ylims)
|
||||
min_x = min(minx)
|
||||
max_x = max(maxx)
|
||||
min_y = min(miny)
|
||||
max_y = max(maxy)
|
||||
return ((min_x, max_x), (min_y, max_y))
|
||||
|
||||
@property
|
||||
def position(self):
|
||||
return self._position
|
||||
|
||||
@position.setter
|
||||
def position(self, new_pos):
|
||||
'''
|
||||
Sets the position of the AMGroup.
|
||||
This offset all of the objects by the specified distance.
|
||||
'''
|
||||
|
||||
if self._position:
|
||||
dx = new_pos[0] - self._position[0]
|
||||
dy = new_pos[0] - self._position[0]
|
||||
else:
|
||||
dx = new_pos[0]
|
||||
dy = new_pos[1]
|
||||
|
||||
for primitive in self.primitives:
|
||||
primitive.offset(dx, dy)
|
||||
|
||||
self._position = new_pos
|
||||
|
||||
class Region(Primitive):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -122,11 +122,27 @@ class GerberCairoContext(GerberContext):
|
|||
def _render_rectangle(self, rectangle, color):
|
||||
ll = map(mul, rectangle.lower_left, self.scale)
|
||||
width, height = tuple(map(mul, (rectangle.width, rectangle.height), map(abs, self.scale)))
|
||||
|
||||
if rectangle.rotation != 0:
|
||||
self.ctx.save()
|
||||
|
||||
center = map(mul, rectangle.position, self.scale)
|
||||
matrix = cairo.Matrix()
|
||||
matrix.translate(center[0], center[1])
|
||||
# For drawing, we already handles the translation
|
||||
ll[0] = ll[0] - center[0]
|
||||
ll[1] = ll[1] - center[1]
|
||||
matrix.rotate(rectangle.rotation)
|
||||
self.ctx.transform(matrix)
|
||||
|
||||
self.ctx.set_source_rgba(color[0], color[1], color[2], self.alpha)
|
||||
self.ctx.set_operator(cairo.OPERATOR_OVER if (rectangle.level_polarity == "dark" and not self.invert) else cairo.OPERATOR_CLEAR)
|
||||
self.ctx.set_line_width(0)
|
||||
self.ctx.rectangle(ll[0], ll[1], width, height)
|
||||
self.ctx.fill()
|
||||
|
||||
if rectangle.rotation != 0:
|
||||
self.ctx.restore()
|
||||
|
||||
def _render_obround(self, obround, color):
|
||||
self._render_circle(obround.subshapes['circle1'], color)
|
||||
|
|
@ -135,6 +151,10 @@ class GerberCairoContext(GerberContext):
|
|||
|
||||
def _render_drill(self, circle, color):
|
||||
self._render_circle(circle, color)
|
||||
|
||||
def _render_amgroup(self, amgroup, color):
|
||||
for primitive in amgroup.primitives:
|
||||
self.render(primitive)
|
||||
|
||||
def _render_test_record(self, primitive, color):
|
||||
self.ctx.select_font_face('monospace', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
|
||||
|
|
|
|||
|
|
@ -150,6 +150,8 @@ class GerberContext(object):
|
|||
self._render_polygon(primitive, color)
|
||||
elif isinstance(primitive, Drill):
|
||||
self._render_drill(primitive, self.drill_color)
|
||||
elif isinstance(primitive, AMGroup):
|
||||
self._render_amgroup(primitive, color)
|
||||
elif isinstance(primitive, TestRecord):
|
||||
self._render_test_record(primitive, color)
|
||||
else:
|
||||
|
|
@ -178,6 +180,9 @@ class GerberContext(object):
|
|||
|
||||
def _render_drill(self, primitive, color):
|
||||
pass
|
||||
|
||||
def _render_amgroup(self, primitive, color):
|
||||
pass
|
||||
|
||||
def _render_test_record(self, primitive, color):
|
||||
pass
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue