Support for LPD and LPC in Gerber. Major changes in Gerber parser.

This commit is contained in:
Juan Pablo Caram
2014-04-12 02:16:39 -04:00
parent 9490501f62
commit 2ed0f73f87
5 changed files with 362 additions and 175 deletions

View File

@@ -16,6 +16,7 @@ from gi.repository import GdkPixbuf
from gi.repository import GLib from gi.repository import GLib
from gi.repository import GObject from gi.repository import GObject
import simplejson as json import simplejson as json
import traceback
import matplotlib import matplotlib
from matplotlib.figure import Figure from matplotlib.figure import Figure
@@ -29,12 +30,15 @@ import urllib
import copy import copy
import random import random
from shapely import speedups
######################################## ########################################
## Imports part of FlatCAM ## ## Imports part of FlatCAM ##
######################################## ########################################
from camlib import * from camlib import *
from FlatCAMObj import * from FlatCAMObj import *
from FlatCAMWorker import Worker from FlatCAMWorker import Worker
from FlatCAMException import *
######################################## ########################################
@@ -55,6 +59,9 @@ class App:
:rtype: App :rtype: App
""" """
if speedups.available:
speedups.enable()
# Needed to interact with the GUI from other threads. # Needed to interact with the GUI from other threads.
GObject.threads_init() GObject.threads_init()
@@ -185,13 +192,10 @@ class App:
def somethreadfunc(app_obj): def somethreadfunc(app_obj):
print "Hello World!" print "Hello World!"
self.message_dialog("Starting", "The best program is starting")
t = threading.Thread(target=somethreadfunc, args=(self,)) t = threading.Thread(target=somethreadfunc, args=(self,))
t.daemon = True t.daemon = True
t.start() t.start()
######################################## ########################################
## START ## ## START ##
######################################## ########################################
@@ -203,14 +207,18 @@ class App:
self.window.set_default_size(900, 600) self.window.set_default_size(900, 600)
self.window.show_all() self.window.show_all()
def message_dialog(self, title, message, type="info"): def message_dialog(self, title, message, kind="info"):
types = {"info": Gtk.MessageType.INFO, types = {"info": Gtk.MessageType.INFO,
"warn": Gtk.MessageType.WARNING, "warn": Gtk.MessageType.WARNING,
"error": Gtk.MessageType.ERROR} "error": Gtk.MessageType.ERROR}
dlg = Gtk.MessageDialog(self.window, 0, types[type], Gtk.ButtonsType.OK, title) dlg = Gtk.MessageDialog(self.window, 0, types[kind], Gtk.ButtonsType.OK, title)
dlg.format_secondary_text(message) dlg.format_secondary_text(message)
dlg.run()
dlg.destroy() def lifecycle():
dlg.run()
dlg.destroy()
GLib.idle_add(lifecycle)
def question_dialog(self, title, message): def question_dialog(self, title, message):
label = Gtk.Label(message) label = Gtk.Label(message)
@@ -879,6 +887,158 @@ class App:
f.close() f.close()
def open_gerber(self, filename):
"""
Opens a Gerber file, parses it and creates a new object for
it in the program. Thread-safe.
:param filename: Gerber file filename
:type filename: str
:return: None
"""
GLib.idle_add(lambda: self.set_progress_bar(0.1, "Opening Gerber ..."))
# How the object should be initialized
def obj_init(gerber_obj, app_obj):
assert isinstance(gerber_obj, FlatCAMGerber)
# Opening the file happens here
GLib.idle_add(lambda: app_obj.set_progress_bar(0.2, "Parsing ..."))
gerber_obj.parse_file(filename)
# Further parsing
GLib.idle_add(lambda: app_obj.set_progress_bar(0.5, "Creating Geometry ..."))
#gerber_obj.create_geometry()
gerber_obj.solid_geometry = gerber_obj.otf_geometry
GLib.idle_add(lambda: app_obj.set_progress_bar(0.6, "Plotting ..."))
# Object name
name = filename.split('/')[-1].split('\\')[-1]
# New object creation and file processing
try:
self.new_object("gerber", name, obj_init)
except:
e = sys.exc_info()
print "ERROR:", e[0]
traceback.print_exc()
self.message_dialog("Failed to create Gerber Object",
"Attempting to create a FlatCAM Gerber Object from " +
"Gerber file failed during processing:\n" +
str(e[0]) + " " + str(e[1]), kind="error")
GLib.timeout_add_seconds(1, lambda: self.set_progress_bar(0.0, "Idle"))
self.collection.delete_active()
return
# Register recent file
self.register_recent("gerber", filename)
# GUI feedback
self.info("Opened: " + filename)
GLib.idle_add(lambda: self.set_progress_bar(1.0, "Done!"))
GLib.timeout_add_seconds(1, lambda: self.set_progress_bar(0.0, "Idle"))
def open_excellon(self, filename):
"""
Opens an Excellon file, parses it and creates a new object for
it in the program. Thread-safe.
:param filename: Excellon file filename
:type filename: str
:return: None
"""
GLib.idle_add(lambda: self.set_progress_bar(0.1, "Opening Excellon ..."))
# How the object should be initialized
def obj_init(excellon_obj, app_obj):
GLib.idle_add(lambda: app_obj.set_progress_bar(0.2, "Parsing ..."))
excellon_obj.parse_file(filename)
excellon_obj.create_geometry()
GLib.idle_add(lambda: app_obj.set_progress_bar(0.6, "Plotting ..."))
# Object name
name = filename.split('/')[-1].split('\\')[-1]
# New object creation and file processing
try:
self.new_object("excellon", name, obj_init)
except:
e = sys.exc_info()
print "ERROR:", e[0]
self.message_dialog("Failed to create Excellon Object",
"Attempting to create a FlatCAM Excellon Object from " +
"Excellon file failed during processing:\n" +
str(e[0]) + " " + str(e[1]), kind="error")
GLib.timeout_add_seconds(1, lambda: self.set_progress_bar(0.0, "Idle"))
self.collection.delete_active()
return
# Register recent file
self.register_recent("excellon", filename)
# GUI feedback
self.info("Opened: " + filename)
GLib.idle_add(lambda: self.set_progress_bar(1.0, "Done!"))
GLib.timeout_add_seconds(1, lambda: self.set_progress_bar(0.0, ""))
def open_gcode(self, filename):
"""
Opens a G-gcode file, parses it and creates a new object for
it in the program. Thread-safe.
:param filename: G-code file filename
:type filename: str
:return: None
"""
# How the object should be initialized
def obj_init(job_obj, app_obj_):
"""
:type app_obj_: App
"""
assert isinstance(app_obj_, App)
GLib.idle_add(lambda: app_obj_.set_progress_bar(0.1, "Opening G-Code ..."))
f = open(filename)
gcode = f.read()
f.close()
job_obj.gcode = gcode
GLib.idle_add(lambda: app_obj_.set_progress_bar(0.2, "Parsing ..."))
job_obj.gcode_parse()
GLib.idle_add(lambda: app_obj_.set_progress_bar(0.6, "Creating geometry ..."))
job_obj.create_geometry()
GLib.idle_add(lambda: app_obj_.set_progress_bar(0.6, "Plotting ..."))
# Object name
name = filename.split('/')[-1].split('\\')[-1]
# New object creation and file processing
try:
self.new_object("cncjob", name, obj_init)
except:
e = sys.exc_info()
print "ERROR:", e[0]
self.message_dialog("Failed to create CNCJob Object",
"Attempting to create a FlatCAM CNCJob Object from " +
"G-Code file failed during processing:\n" +
str(e[0]) + " " + str(e[1]), kind="error")
GLib.timeout_add_seconds(1, lambda: self.set_progress_bar(0.0, "Idle"))
self.collection.delete_active()
return
# Register recent file
self.register_recent("cncjob", filename)
# GUI feedback
self.info("Opened: " + filename)
GLib.idle_add(lambda: self.set_progress_bar(1.0, "Done!"))
GLib.timeout_add_seconds(1, lambda: self.set_progress_bar(0.0, ""))
######################################## ########################################
## EVENT HANDLERS ## ## EVENT HANDLERS ##
######################################## ########################################
@@ -1980,29 +2140,6 @@ class App:
self.info("Save cancelled.") # print("Cancel clicked") self.info("Save cancelled.") # print("Cancel clicked")
dialog.destroy() dialog.destroy()
def open_gerber(self, filename):
GLib.idle_add(lambda: self.set_progress_bar(0.1, "Opening Gerber ..."))
def obj_init(gerber_obj, app_obj):
assert isinstance(gerber_obj, FlatCAMGerber)
# Opening the file happens here
GLib.idle_add(lambda: app_obj.set_progress_bar(0.2, "Parsing ..."))
gerber_obj.parse_file(filename)
# Further parsing
GLib.idle_add(lambda: app_obj.set_progress_bar(0.5, "Creating Geometry ..."))
gerber_obj.create_geometry()
GLib.idle_add(lambda: app_obj.set_progress_bar(0.6, "Plotting ..."))
name = filename.split('/')[-1].split('\\')[-1]
self.new_object("gerber", name, obj_init)
self.register_recent("gerber", filename)
self.info("Opened: " + filename)
GLib.idle_add(lambda: self.set_progress_bar(1.0, "Done!"))
GLib.timeout_add_seconds(1, lambda: self.set_progress_bar(0.0, "Idle"))
def on_fileopengerber(self, param): def on_fileopengerber(self, param):
""" """
Callback for menu item File->Open Gerber. Defines a function that is then passed Callback for menu item File->Open Gerber. Defines a function that is then passed
@@ -2015,23 +2152,6 @@ class App:
self.file_chooser_action(lambda ao, filename: self.open_gerber(filename)) self.file_chooser_action(lambda ao, filename: self.open_gerber(filename))
def open_excellon(self, filename):
GLib.idle_add(lambda: self.set_progress_bar(0.1, "Opening Excellon ..."))
def obj_init(excellon_obj, app_obj):
GLib.idle_add(lambda: app_obj.set_progress_bar(0.2, "Parsing ..."))
excellon_obj.parse_file(filename)
excellon_obj.create_geometry()
GLib.idle_add(lambda: app_obj.set_progress_bar(0.6, "Plotting ..."))
name = filename.split('/')[-1].split('\\')[-1]
self.new_object("excellon", name, obj_init)
self.register_recent("excellon", filename)
self.info("Opened: " + filename)
GLib.idle_add(lambda: self.set_progress_bar(1.0, "Done!"))
GLib.timeout_add_seconds(1, lambda: self.set_progress_bar(0.0, ""))
def on_fileopenexcellon(self, param): def on_fileopenexcellon(self, param):
""" """
Callback for menu item File->Open Excellon. Defines a function that is then passed Callback for menu item File->Open Excellon. Defines a function that is then passed
@@ -2044,38 +2164,6 @@ class App:
self.file_chooser_action(lambda ao, filename: self.open_excellon(filename)) self.file_chooser_action(lambda ao, filename: self.open_excellon(filename))
def open_gcode(self, filename):
def obj_init(job_obj, app_obj_):
"""
:type app_obj_: App
"""
assert isinstance(app_obj_, App)
GLib.idle_add(lambda: app_obj_.set_progress_bar(0.1, "Opening G-Code ..."))
f = open(filename)
gcode = f.read()
f.close()
job_obj.gcode = gcode
GLib.idle_add(lambda: app_obj_.set_progress_bar(0.2, "Parsing ..."))
job_obj.gcode_parse()
GLib.idle_add(lambda: app_obj_.set_progress_bar(0.6, "Creating geometry ..."))
job_obj.create_geometry()
GLib.idle_add(lambda: app_obj_.set_progress_bar(0.6, "Plotting ..."))
name = filename.split('/')[-1].split('\\')[-1]
self.new_object("cncjob", name, obj_init)
self.register_recent("cncjob", filename)
self.info("Opened: " + filename)
GLib.idle_add(lambda: self.set_progress_bar(1.0, "Done!"))
GLib.timeout_add_seconds(1, lambda: self.set_progress_bar(0.0, ""))
def on_fileopengcode(self, param): def on_fileopengcode(self, param):
""" """
Callback for menu item File->Open G-Code. Defines a function that is then passed Callback for menu item File->Open G-Code. Defines a function that is then passed

View File

@@ -137,77 +137,6 @@ THE SOFTWARE.</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="stock">gtk-open</property> <property name="stock">gtk-open</property>
</object> </object>
<object class="GtkDialog" id="question_dialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="question_box">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area1">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box40">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="image22">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="pixbuf">share/warning.png</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_warning">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">12</property>
<property name="margin_right">12</property>
<property name="margin_top">12</property>
<property name="margin_bottom">12</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">label</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkOffscreenWindow" id="offscreenwindow_dblsided"> <object class="GtkOffscreenWindow" id="offscreenwindow_dblsided">
<property name="can_focus">False</property> <property name="can_focus">False</property>
<child> <child>

View File

@@ -304,6 +304,12 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
[poly['polygon'] for poly in self.regions] + \ [poly['polygon'] for poly in self.regions] + \
self.flash_geometry self.flash_geometry
# Make sure geometry is iterable.
try:
_ = iter(geometry)
except TypeError:
geometry = [geometry]
if self.options["multicolored"]: if self.options["multicolored"]:
linespec = '-' linespec = '-'
else: else:

212
camlib.py
View File

@@ -651,6 +651,9 @@ class Gerber (Geometry):
# Geometry from flashes # Geometry from flashes
self.flash_geometry = [] self.flash_geometry = []
# On-the-fly geometry. Initialized to an empty polygon
self.otf_geometry = Polygon()
# Aperture Macros # Aperture Macros
# TODO: Make sure these can be serialized # TODO: Make sure these can be serialized
self.aperture_macros = {} self.aperture_macros = {}
@@ -686,16 +689,20 @@ class Gerber (Geometry):
# May begin with G54 but that is deprecated # May begin with G54 but that is deprecated
self.tool_re = re.compile(r'^(?:G54)?D(\d\d+)\*$') self.tool_re = re.compile(r'^(?:G54)?D(\d\d+)\*$')
# G01 - Linear interpolation plus flashes # G01... - Linear interpolation plus flashes with coordinates
# Operation code (D0x) missing is deprecated... oh well I will support it. # Operation code (D0x) missing is deprecated... oh well I will support it.
self.lin_re = re.compile(r'^(?:G0?(1))?(?:X(-?\d+))?(?:Y(-?\d+))?(?:D0?([123]))?\*$') self.lin_re = re.compile(r'^(?:G0?(1))?(?=.*X(-?\d+))?(?=.*Y(-?\d+))?[XY][^DIJ]*(?:D0?([123]))?\*$')
self.setlin_re = re.compile(r'^(?:G0?1)\*') #
self.opcode_re = re.compile(r'^D0?([123])\*$')
# G02/3 - Circular interpolation # G02/3... - Circular interpolation with coordinates
# 2-clockwise, 3-counterclockwise # 2-clockwise, 3-counterclockwise
self.circ_re = re.compile(r'^(?:G0?([23]))?(?:X(-?\d+))?(?:Y(-?\d+))' + # Operation code (D0x) missing is deprecated... oh well I will support it.
'?(?:I(-?\d+))?(?:J(-?\d+))?D0([12])\*$') # Optional start with G02 or G03, optional end with D01 or D02 with
# optional coordinates but at least one in any order.
self.circ_re = re.compile(r'^(?:G0?([23]))?(?=.*X(-?\d+))?(?=.*Y(-?\d+))' +
'?(?=.*I(-?\d+))?(?=.*J(-?\d+))?[XYIJ][^D]*(?:D0([12]))?\*$')
# G01/2/3 Occurring without coordinates # G01/2/3 Occurring without coordinates
self.interp_re = re.compile(r'^(?:G0?([123]))\*') self.interp_re = re.compile(r'^(?:G0?([123]))\*')
@@ -1038,6 +1045,7 @@ class Gerber (Geometry):
current_y = None current_y = None
# Absolute or Relative/Incremental coordinates # Absolute or Relative/Incremental coordinates
# Not implemented
absolute = True absolute = True
# How to interpret circular interpolation: SINGLE or MULTI # How to interpret circular interpolation: SINGLE or MULTI
@@ -1046,6 +1054,12 @@ class Gerber (Geometry):
# Indicates we are parsing an aperture macro # Indicates we are parsing an aperture macro
current_macro = None current_macro = None
# Indicates the current polarity: D-Dark, C-Clear
current_polarity = 'D'
# If a region is being defined
making_region = False
#### Parsing starts here #### #### Parsing starts here ####
line_num = 0 line_num = 0
for gline in glines: for gline in glines:
@@ -1107,19 +1121,39 @@ class Gerber (Geometry):
path.append([current_x, current_y]) path.append([current_x, current_y])
last_path_aperture = current_aperture last_path_aperture = current_aperture
# Pen up: finish path
elif current_operation_code == 2: elif current_operation_code == 2:
if len(path) > 1: if len(path) > 1:
if last_path_aperture is None:
print "Warning: No aperture defined for curent path. (%d)" % line_num # self.paths.append({"linestring": LineString(path),
self.paths.append({"linestring": LineString(path), # "aperture": last_path_aperture})
"aperture": last_path_aperture})
# --- OTF ---
if making_region:
geo = Polygon(path)
else:
if last_path_aperture is None:
print "Warning: No aperture defined for curent path. (%d)" % line_num
width = self.apertures[last_path_aperture]["size"]
geo = LineString(path).buffer(width/2)
if current_polarity == 'D':
self.otf_geometry = self.otf_geometry.union(geo)
else:
self.otf_geometry = self.otf_geometry.difference(geo)
path = [[current_x, current_y]] # Start new path path = [[current_x, current_y]] # Start new path
# Flash # Flash
elif current_operation_code == 3: elif current_operation_code == 3:
self.flashes.append({"loc": Point([current_x, current_y]), # self.flashes.append({"loc": Point([current_x, current_y]),
"aperture": current_aperture}) # "aperture": current_aperture})
# --- OTF ---
flash = Gerber.create_flash_geometry(Point([current_x, current_y]),
self.apertures[current_aperture])
if current_polarity == 'D':
self.otf_geometry = self.otf_geometry.union(flash)
else:
self.otf_geometry = self.otf_geometry.difference(flash)
continue continue
@@ -1168,8 +1202,17 @@ class Gerber (Geometry):
if len(path) > 1: if len(path) > 1:
if last_path_aperture is None: if last_path_aperture is None:
print "Warning: No aperture defined for curent path. (%d)" % line_num print "Warning: No aperture defined for curent path. (%d)" % line_num
self.paths.append({"linestring": LineString(path), # self.paths.append({"linestring": LineString(path),
"aperture": last_path_aperture}) # "aperture": last_path_aperture})
# --- OTF ---
width = self.apertures[last_path_aperture]["size"]
buffered = LineString(path).buffer(width/2)
if current_polarity == 'D':
self.otf_geometry = self.otf_geometry.union(buffered)
else:
self.otf_geometry = self.otf_geometry.difference(buffered)
current_x = x current_x = x
current_y = y current_y = y
path = [[current_x, current_y]] # Start new path path = [[current_x, current_y]] # Start new path
@@ -1204,6 +1247,19 @@ class Gerber (Geometry):
if quadrant_mode == 'SINGLE': if quadrant_mode == 'SINGLE':
print "Warning: Single quadrant arc are not implemented yet. (%d)" % line_num print "Warning: Single quadrant arc are not implemented yet. (%d)" % line_num
### Operation code alone
match = self.opcode_re.search(gline)
if match:
current_operation_code = int(match.group(1))
if current_operation_code == 3:
flash = Gerber.create_flash_geometry(Point(path[-1]),
self.apertures[current_aperture])
if current_polarity == 'D':
self.otf_geometry = self.otf_geometry.union(flash)
else:
self.otf_geometry = self.otf_geometry.difference(flash)
continue
### G74/75* - Single or multiple quadrant arcs ### G74/75* - Single or multiple quadrant arcs
match = self.quad_re.search(gline) match = self.quad_re.search(gline)
if match: if match:
@@ -1213,20 +1269,49 @@ class Gerber (Geometry):
quadrant_mode = 'MULTI' quadrant_mode = 'MULTI'
continue continue
### G36* - Begin region
if self.regionon_re.search(gline):
if len(path) > 1:
# Take care of what is left in the path
width = self.apertures[last_path_aperture]["size"]
geo = LineString(path).buffer(width/2)
if current_polarity == 'D':
self.otf_geometry = self.otf_geometry.union(geo)
else:
self.otf_geometry = self.otf_geometry.difference(geo)
path = [path[-1]]
making_region = True
continue
### G37* - End region ### G37* - End region
if self.regionoff_re.search(gline): if self.regionoff_re.search(gline):
making_region = False
# Only one path defines region? # Only one path defines region?
# This can happen if D02 happened before G37 and
# is not and error.
if len(path) < 3: if len(path) < 3:
print "ERROR: Path contains less than 3 points:" # print "ERROR: Path contains less than 3 points:"
print path # print path
print "Line (%d): " % line_num, gline # print "Line (%d): " % line_num, gline
path = [] # path = []
#path = [[current_x, current_y]]
continue continue
# For regions we may ignore an aperture that is None # For regions we may ignore an aperture that is None
self.regions.append({"polygon": Polygon(path), # self.regions.append({"polygon": Polygon(path),
"aperture": last_path_aperture}) # "aperture": last_path_aperture})
#path = []
# --- OTF ---
region = Polygon(path)
if not region.is_valid:
region = region.buffer(0)
if current_polarity == 'D':
self.otf_geometry = self.otf_geometry.union(region)
else:
self.otf_geometry = self.otf_geometry.difference(region)
path = [[current_x, current_y]] # Start new path path = [[current_x, current_y]] # Start new path
continue continue
@@ -1252,6 +1337,22 @@ class Gerber (Geometry):
current_aperture = match.group(1) current_aperture = match.group(1)
continue continue
### Polarity change
# Example: %LPD*% or %LPC*%
match = self.lpol_re.search(gline)
if match:
if len(path) > 1 and current_polarity != match.group(1):
width = self.apertures[last_path_aperture]["size"]
geo = LineString(path).buffer(width/2)
if current_polarity == 'D':
self.otf_geometry = self.otf_geometry.union(geo)
else:
self.otf_geometry = self.otf_geometry.difference(geo)
path = [path[-1]]
current_polarity = match.group(1)
continue
### Number format ### Number format
# Example: %FSLAX24Y24*% # Example: %FSLAX24Y24*%
# TODO: This is ignoring most of the format. Implement the rest. # TODO: This is ignoring most of the format. Implement the rest.
@@ -1297,8 +1398,71 @@ class Gerber (Geometry):
if len(path) > 1: if len(path) > 1:
# EOF, create shapely LineString if something still in path # EOF, create shapely LineString if something still in path
self.paths.append({"linestring": LineString(path), # self.paths.append({"linestring": LineString(path),
"aperture": last_path_aperture}) # "aperture": last_path_aperture})
width = self.apertures[last_path_aperture]["size"]
geo = LineString(path).buffer(width/2)
if current_polarity == 'D':
self.otf_geometry = self.otf_geometry.union(geo)
else:
self.otf_geometry = self.otf_geometry.difference(geo)
@staticmethod
def create_flash_geometry(location, aperture):
if type(location) == list:
location = Point(location)
if aperture['type'] == 'C': # Circles
return location.buffer(aperture['size']/2)
if aperture['type'] == 'R': # Rectangles
loc = location.coords[0]
width = aperture['width']
height = aperture['height']
minx = loc[0] - width/2
maxx = loc[0] + width/2
miny = loc[1] - height/2
maxy = loc[1] + height/2
return shply_box(minx, miny, maxx, maxy)
if aperture['type'] == 'O': # Obround
loc = location.coords[0]
width = aperture['width']
height = aperture['height']
if width > height:
p1 = Point(loc[0] + 0.5*(width-height), loc[1])
p2 = Point(loc[0] - 0.5*(width-height), loc[1])
c1 = p1.buffer(height*0.5)
c2 = p2.buffer(height*0.5)
else:
p1 = Point(loc[0], loc[1] + 0.5*(height-width))
p2 = Point(loc[0], loc[1] - 0.5*(height-width))
c1 = p1.buffer(width*0.5)
c2 = p2.buffer(width*0.5)
return cascaded_union([c1, c2]).convex_hull
if aperture['type'] == 'P': # Regular polygon
loc = location.coords[0]
diam = aperture['diam']
n_vertices = aperture['nVertices']
points = []
for i in range(0, n_vertices):
x = loc[0] + diam * (cos(2 * pi * i / n_vertices))
y = loc[1] + diam * (sin(2 * pi * i / n_vertices))
points.append((x, y))
ply = Polygon(points)
if 'rotation' in aperture:
ply = affinity.rotate(ply, aperture['rotation'])
return ply
if aperture['type'] == 'AM': # Aperture Macro
loc = location.coords[0]
flash_geo = aperture['macro'].make_geometry(aperture['modifiers'])
return affinity.translate(flash_geo, xoff=loc[0], yoff=loc[1])
return None
def do_flashes(self): def do_flashes(self):
""" """

View File

@@ -1 +1 @@
[{"kind": "excellon", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\TFTadapter.drl"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\PlacaReles-F_Cu.gtl"}, {"kind": "excellon", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\PlacaReles.drl"}, {"kind": "excellon", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\BLDC2003Through.drl"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\PhD\\PLLs\\RTWO\\Project Outputs for RTWO1\\PCB1.GTL"}, {"kind": "project", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\RTWO_fc5_3.fcproj"}, {"kind": "project", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\RTWO_fc5_2.fcproj"}, {"kind": "project", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\RTWO_fc5.fcproj"}, {"kind": "cncjob", "filename": "Z:\\CNC\\testpcb\\2\\noname-F_Cu_ISOLATION_GCODE3.ngc"}, {"kind": "cncjob", "filename": "C:\\Users\\jpcaram\\Dropbox\\PhD\\PLLs\\RTWO\\RTWO1_CNC\\iso_bottom1.gcode"}] [{"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\Example1_copper_bottom_Gndplane_modified.gbr"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\PhD\\Kenney\\Project Outputs for AnalogPredistortion1\\apd.GTL"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\WindMills - Bottom Copper 2.gbr"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\CC_LOAD_7000164-00_REV_A_copper_top.gbr"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\Example1_copper_bottom_Gndplane.gbr"}, {"kind": "excellon", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\TFTadapter.drl"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\PlacaReles-F_Cu.gtl"}, {"kind": "excellon", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\PlacaReles.drl"}, {"kind": "excellon", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\BLDC2003Through.drl"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\PhD\\PLLs\\RTWO\\Project Outputs for RTWO1\\PCB1.GTL"}]