Patched Gerber parsing to support some non-compliant instructions.
This commit is contained in:
24
FlatCAM.py
24
FlatCAM.py
@@ -1,7 +1,9 @@
|
|||||||
############################################################
|
############################################################
|
||||||
# Author: Juan Pablo Caram #
|
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||||
|
# http://caram.cl/software/flatcam #
|
||||||
|
# Author: Juan Pablo Caram (c) #
|
||||||
# Date: 2/5/2014 #
|
# Date: 2/5/2014 #
|
||||||
# caram.cl #
|
# MIT Licence #
|
||||||
############################################################
|
############################################################
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
@@ -553,7 +555,7 @@ class App:
|
|||||||
self.builder = Gtk.Builder()
|
self.builder = Gtk.Builder()
|
||||||
self.builder.add_from_file(self.gladefile)
|
self.builder.add_from_file(self.gladefile)
|
||||||
self.window = self.builder.get_object("window1")
|
self.window = self.builder.get_object("window1")
|
||||||
self.window.set_title("FlatCAM")
|
self.window.set_title("FlatCAM - Alpha 1 UNSTABLE - Check for updates!")
|
||||||
self.position_label = self.builder.get_object("label3")
|
self.position_label = self.builder.get_object("label3")
|
||||||
self.grid = self.builder.get_object("grid1")
|
self.grid = self.builder.get_object("grid1")
|
||||||
self.notebook = self.builder.get_object("notebook1")
|
self.notebook = self.builder.get_object("notebook1")
|
||||||
@@ -969,9 +971,9 @@ class App:
|
|||||||
|
|
||||||
def set_progress_bar(self, percentage, text=""):
|
def set_progress_bar(self, percentage, text=""):
|
||||||
"""
|
"""
|
||||||
Sets the application's progress bar to a given fraction and text.
|
Sets the application's progress bar to a given frac_digits and text.
|
||||||
|
|
||||||
:param percentage: The fraction (0.0-1.0) of the progress.
|
:param percentage: The frac_digits (0.0-1.0) of the progress.
|
||||||
:type percentage: float
|
:type percentage: float
|
||||||
:param text: Text to display on the progress bar.
|
:param text: Text to display on the progress bar.
|
||||||
:type text: str
|
:type text: str
|
||||||
@@ -1260,6 +1262,18 @@ class App:
|
|||||||
########################################
|
########################################
|
||||||
## EVENT HANDLERS ##
|
## EVENT HANDLERS ##
|
||||||
########################################
|
########################################
|
||||||
|
def on_about(self, widget):
|
||||||
|
"""
|
||||||
|
Opens the 'About' dialog box.
|
||||||
|
|
||||||
|
:param widget: Ignored.
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
about = self.builder.get_object("aboutdialog")
|
||||||
|
response = about.run()
|
||||||
|
about.destroy()
|
||||||
|
|
||||||
|
|
||||||
def on_create_mirror(self, widget):
|
def on_create_mirror(self, widget):
|
||||||
"""
|
"""
|
||||||
Creates a mirror image of a Gerber object to be used as a bottom
|
Creates a mirror image of a Gerber object to be used as a bottom
|
||||||
|
|||||||
56
FlatCAM.ui
56
FlatCAM.ui
@@ -1,6 +1,61 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<interface>
|
<interface>
|
||||||
<!-- interface-requires gtk+ 3.0 -->
|
<!-- interface-requires gtk+ 3.0 -->
|
||||||
|
<object class="GtkAboutDialog" id="aboutdialog">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="border_width">5</property>
|
||||||
|
<property name="type_hint">dialog</property>
|
||||||
|
<property name="program_name">FlatCAM</property>
|
||||||
|
<property name="version">Version Alpha 1 (2014/02) - UNSTABLE</property>
|
||||||
|
<property name="copyright" translatable="yes">(c) 2014 Juan Pablo Caram</property>
|
||||||
|
<property name="comments" translatable="yes">2D Post-processing for Manufacturing specialized in
|
||||||
|
Printed Circuit Boards</property>
|
||||||
|
<property name="website">http://caram.cl/software/flatcam/</property>
|
||||||
|
<property name="website_label" translatable="yes">Caram.cl/software/flatcam</property>
|
||||||
|
<property name="license" translatable="yes">The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Juan Pablo Caram
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.</property>
|
||||||
|
<child internal-child="vbox">
|
||||||
|
<object class="GtkBox" id="aboutdialog-vbox1">
|
||||||
|
<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="aboutdialog-action_area1">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
</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>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
<object class="GtkImage" id="image1">
|
<object class="GtkImage" id="image1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
@@ -2673,6 +2728,7 @@ to application defaults.</property>
|
|||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
<property name="use_stock">True</property>
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_about" swapped="no"/>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|||||||
336
camlib.py
336
camlib.py
@@ -1,7 +1,9 @@
|
|||||||
############################################################
|
############################################################
|
||||||
# Author: Juan Pablo Caram #
|
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||||
|
# http://caram.cl/software/flatcam #
|
||||||
|
# Author: Juan Pablo Caram (c) #
|
||||||
# Date: 2/5/2014 #
|
# Date: 2/5/2014 #
|
||||||
# caram.cl #
|
# MIT Licence #
|
||||||
############################################################
|
############################################################
|
||||||
|
|
||||||
from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos
|
from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos
|
||||||
@@ -25,6 +27,7 @@ import simplejson as json
|
|||||||
# TODO: Commented for FlatCAM packaging with cx_freeze
|
# TODO: Commented for FlatCAM packaging with cx_freeze
|
||||||
#from matplotlib.pyplot import plot
|
#from matplotlib.pyplot import plot
|
||||||
|
|
||||||
|
|
||||||
class Geometry:
|
class Geometry:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Units (in or mm)
|
# Units (in or mm)
|
||||||
@@ -232,10 +235,10 @@ class Gerber (Geometry):
|
|||||||
Geometry.__init__(self)
|
Geometry.__init__(self)
|
||||||
|
|
||||||
# Number format
|
# Number format
|
||||||
self.digits = 3
|
self.int_digits = 3
|
||||||
"""Number of integer digits in Gerber numbers. Used during parsing."""
|
"""Number of integer digits in Gerber numbers. Used during parsing."""
|
||||||
|
|
||||||
self.fraction = 4
|
self.frac_digits = 4
|
||||||
"""Number of fraction digits in Gerber numbers. Used during parsing."""
|
"""Number of fraction digits in Gerber numbers. Used during parsing."""
|
||||||
|
|
||||||
## Gerber elements ##
|
## Gerber elements ##
|
||||||
@@ -264,10 +267,72 @@ class Gerber (Geometry):
|
|||||||
# Attributes to be included in serialization
|
# Attributes to be included in serialization
|
||||||
# Always append to it because it carries contents
|
# Always append to it because it carries contents
|
||||||
# from Geometry.
|
# from Geometry.
|
||||||
self.ser_attrs += ['digits', 'fraction', 'apertures', 'paths',
|
self.ser_attrs += ['int_digits', 'frac_digits', 'apertures', 'paths',
|
||||||
'buffered_paths', 'regions', 'flashes',
|
'buffered_paths', 'regions', 'flashes',
|
||||||
'flash_geometry']
|
'flash_geometry']
|
||||||
|
|
||||||
|
#### Parser patterns ####
|
||||||
|
# FS - Format Specification
|
||||||
|
# The format of X and Y must be the same!
|
||||||
|
# L-omit leading zeros, T-omit trailing zeros
|
||||||
|
# A-absolute notation, I-incremental notation
|
||||||
|
self.fmt_re = re.compile(r'%FS([LT])([AI])X(\d)(\d)Y\d\d\*%$')
|
||||||
|
|
||||||
|
# Mode (IN/MM)
|
||||||
|
self.mode_re = re.compile(r'^%MO(IN|MM)\*%$')
|
||||||
|
|
||||||
|
# Comment G04|G4
|
||||||
|
self.comm_re = re.compile(r'^G0?4(.*)$')
|
||||||
|
|
||||||
|
# AD - Aperture definition
|
||||||
|
self.ad_re = re.compile(r'^%ADD(\d\d+)([a-zA-Z0-9]*),(.*)\*%$')
|
||||||
|
|
||||||
|
# AM - Aperture Macro
|
||||||
|
# Beginning of macro (Ends with *%):
|
||||||
|
self.am_re = re.compile(r'^%AM([a-zA-Z0-9]*)\*')
|
||||||
|
|
||||||
|
# Tool change
|
||||||
|
# May begin with G54 but that is deprecated
|
||||||
|
self.tool_re = re.compile(r'^(?:G54)?D(\d\d+)\*$')
|
||||||
|
|
||||||
|
# G01 - Linear interpolation plus flashes
|
||||||
|
# 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.setlin_re = re.compile(r'^(?:G0?1)\*')
|
||||||
|
|
||||||
|
# G02/3 - Circular interpolation
|
||||||
|
# 2-clockwise, 3-counterclockwise
|
||||||
|
self.circ_re = re.compile(r'^(?:G0?([23]))?(?:X(-?\d+))?(?:Y(-?\d+))' +
|
||||||
|
'?(?:I(-?\d+))?(?:J(-?\d+))?D0([12])\*$')
|
||||||
|
|
||||||
|
# G01/2/3 Occurring without coordinates
|
||||||
|
self.interp_re = re.compile(r'^(?:G0?([123]))\*')
|
||||||
|
|
||||||
|
# Single D74 or multi D75 quadrant for circular interpolation
|
||||||
|
self.quad_re = re.compile(r'^G7([45])\*$')
|
||||||
|
|
||||||
|
# Region mode on
|
||||||
|
# In region mode, D01 starts a region
|
||||||
|
# and D02 ends it. A new region can be started again
|
||||||
|
# with D01. All contours must be closed before
|
||||||
|
# D02 or G37.
|
||||||
|
self.regionon_re = re.compile(r'^G36\*$')
|
||||||
|
|
||||||
|
# Region mode off
|
||||||
|
# Will end a region and come off region mode.
|
||||||
|
# All contours must be closed before D02 or G37.
|
||||||
|
self.regionoff_re = re.compile(r'^G37\*$')
|
||||||
|
|
||||||
|
# End of file
|
||||||
|
self.eof_re = re.compile(r'^M02\*')
|
||||||
|
|
||||||
|
# IP - Image polarity
|
||||||
|
self.pol_re = re.compile(r'^%IP(POS|NEG)\*%$')
|
||||||
|
|
||||||
|
# LP - Level polarity
|
||||||
|
self.lpol_re = re.compile(r'^%LP([DC])\*%$')
|
||||||
|
|
||||||
def scale(self, factor):
|
def scale(self, factor):
|
||||||
"""
|
"""
|
||||||
Scales the objects' geometry on the XY plane by a given factor.
|
Scales the objects' geometry on the XY plane by a given factor.
|
||||||
@@ -343,16 +408,20 @@ class Gerber (Geometry):
|
|||||||
:return: Identifier of the aperture.
|
:return: Identifier of the aperture.
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
|
|
||||||
indexstar = gline.find("*")
|
indexstar = gline.find("*")
|
||||||
indexc = gline.find("C,")
|
indexc = gline.find("C,")
|
||||||
if indexc != -1: # Circle, example: %ADD11C,0.1*%
|
if indexc != -1: # Circle, example: %ADD11C,0.1*%
|
||||||
apid = gline[4:indexc]
|
# Found some Gerber with a leading zero in the aperture id and the
|
||||||
|
# referenced it without the zero, so this is a hack to handle that.
|
||||||
|
apid = str(int(gline[4:indexc]))
|
||||||
self.apertures[apid] = {"type": "C",
|
self.apertures[apid] = {"type": "C",
|
||||||
"size": float(gline[indexc+2:indexstar])}
|
"size": float(gline[indexc+2:indexstar])}
|
||||||
return apid
|
return apid
|
||||||
indexr = gline.find("R,")
|
indexr = gline.find("R,")
|
||||||
if indexr != -1: # Rectangle, example: %ADD15R,0.05X0.12*%
|
if indexr != -1: # Rectangle, example: %ADD15R,0.05X0.12*%
|
||||||
apid = gline[4:indexr]
|
# Hack explained above
|
||||||
|
apid = str(int(gline[4:indexr]))
|
||||||
indexx = gline.find("X")
|
indexx = gline.find("X")
|
||||||
self.apertures[apid] = {"type": "R",
|
self.apertures[apid] = {"type": "R",
|
||||||
"width": float(gline[indexr+2:indexx]),
|
"width": float(gline[indexr+2:indexx]),
|
||||||
@@ -360,7 +429,8 @@ class Gerber (Geometry):
|
|||||||
return apid
|
return apid
|
||||||
indexo = gline.find("O,")
|
indexo = gline.find("O,")
|
||||||
if indexo != -1: # Obround
|
if indexo != -1: # Obround
|
||||||
apid = gline[4:indexo]
|
# Hack explained above
|
||||||
|
apid = str(int(gline[4:indexo]))
|
||||||
indexx = gline.find("X")
|
indexx = gline.find("X")
|
||||||
self.apertures[apid] = {"type": "O",
|
self.apertures[apid] = {"type": "O",
|
||||||
"width": float(gline[indexo+2:indexx]),
|
"width": float(gline[indexo+2:indexx]),
|
||||||
@@ -381,67 +451,148 @@ class Gerber (Geometry):
|
|||||||
|
|
||||||
def parse_lines(self, glines):
|
def parse_lines(self, glines):
|
||||||
"""
|
"""
|
||||||
Main Gerber parser.
|
Main Gerber parser. Reads Gerber and populates ``self.paths``, ``self.apertures``,
|
||||||
|
``self.flashes``, ``self.regions`` and ``self.units``.
|
||||||
|
|
||||||
|
:param glines: Gerber code as list of strings, each
|
||||||
|
element being one line of the source file.
|
||||||
|
:type glines: list
|
||||||
|
:return: None
|
||||||
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Mode (IN/MM)
|
|
||||||
mode_re = re.compile(r'^%MO(IN|MM)\*%$')
|
|
||||||
|
|
||||||
path = [] # Coordinates of the current path
|
path = [] # Coordinates of the current path
|
||||||
|
|
||||||
last_path_aperture = None
|
last_path_aperture = None
|
||||||
current_aperture = None
|
current_aperture = None
|
||||||
|
|
||||||
|
# 1,2 or 3 from "G01", "G02" or "G03"
|
||||||
|
current_interpolation_mode = None
|
||||||
|
|
||||||
|
# 1 or 2 from "D01" or "D02"
|
||||||
|
# Note this is to support deprecated Gerber not putting
|
||||||
|
# an operation code at the end of every coordinate line.
|
||||||
|
current_operation_code = None
|
||||||
|
|
||||||
|
# Current coordinates
|
||||||
|
current_x = None
|
||||||
|
current_y = None
|
||||||
|
|
||||||
for gline in glines:
|
for gline in glines:
|
||||||
|
|
||||||
if gline.find("D01*") != -1: # pen down
|
# Linear interpolation plus flashes
|
||||||
path.append(coord(gline, self.digits, self.fraction))
|
match = self.lin_re.search(gline)
|
||||||
last_path_aperture = current_aperture
|
if match:
|
||||||
|
# Parse coordinates
|
||||||
|
if match.group(2) is not None:
|
||||||
|
current_x = parse_gerber_number(match.group(2), self.frac_digits)
|
||||||
|
if match.group(3) is not None:
|
||||||
|
current_y = parse_gerber_number(match.group(3), self.frac_digits)
|
||||||
|
|
||||||
|
# Parse operation code
|
||||||
|
if match.group(4) is not None:
|
||||||
|
current_operation_code = match.group(4)
|
||||||
|
|
||||||
|
# Pen down: add segment
|
||||||
|
if current_operation_code == '1':
|
||||||
|
path.append([current_x, current_y])
|
||||||
|
last_path_aperture = current_aperture
|
||||||
|
|
||||||
|
# Pen up: finish path
|
||||||
|
elif current_operation_code == '2':
|
||||||
|
if len(path) > 1:
|
||||||
|
self.paths.append({"linestring": LineString(path),
|
||||||
|
"aperture": last_path_aperture})
|
||||||
|
path = [[current_x, current_y]]
|
||||||
|
|
||||||
|
# Flash
|
||||||
|
elif current_operation_code == '3':
|
||||||
|
self.flashes.append({"loc": [current_x, current_y],
|
||||||
|
"aperture": current_aperture})
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if gline.find("D02*") != -1: # pen up
|
# if gline.find("D01*") != -1: # pen down
|
||||||
if len(path) > 1:
|
# path.append(parse_gerber_coords(gline, self.int_digits, self.frac_digits))
|
||||||
# Path completed, create shapely LineString
|
# last_path_aperture = current_aperture
|
||||||
self.paths.append({"linestring": LineString(path),
|
# continue
|
||||||
"aperture": last_path_aperture})
|
#
|
||||||
path = [coord(gline, self.digits, self.fraction)]
|
# if gline.find("D02*") != -1: # pen up
|
||||||
continue
|
# if len(path) > 1:
|
||||||
|
# # Path completed, create shapely LineString
|
||||||
indexd3 = gline.find("D03*")
|
# self.paths.append({"linestring": LineString(path),
|
||||||
if indexd3 > 0: # Flash
|
# "aperture": last_path_aperture})
|
||||||
self.flashes.append({"loc": coord(gline, self.digits, self.fraction),
|
# path = [parse_gerber_coords(gline, self.int_digits, self.frac_digits)]
|
||||||
"aperture": current_aperture})
|
# continue
|
||||||
continue
|
#
|
||||||
if indexd3 == 0: # Flash?
|
# indexd3 = gline.find("D03*")
|
||||||
print "WARNING: Uninplemented flash style:", gline
|
# if indexd3 > 0: # Flash
|
||||||
continue
|
# self.flashes.append({"loc": parse_gerber_coords(gline, self.int_digits, self.frac_digits),
|
||||||
|
# "aperture": current_aperture})
|
||||||
if gline.find("G37*") != -1: # end region
|
# continue
|
||||||
|
# if indexd3 == 0: # Flash?
|
||||||
|
# print "WARNING: Uninplemented flash style:", gline
|
||||||
|
# continue
|
||||||
|
|
||||||
|
# End region
|
||||||
|
if self.regionoff_re.search(gline):
|
||||||
# Only one path defines region?
|
# Only one path defines region?
|
||||||
self.regions.append({"polygon": Polygon(path),
|
self.regions.append({"polygon": Polygon(path),
|
||||||
"aperture": last_path_aperture})
|
"aperture": last_path_aperture})
|
||||||
path = []
|
path = []
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# if gline.find("G37*") != -1: # end region
|
||||||
|
# # Only one path defines region?
|
||||||
|
# self.regions.append({"polygon": Polygon(path),
|
||||||
|
# "aperture": last_path_aperture})
|
||||||
|
# path = []
|
||||||
|
# continue
|
||||||
|
|
||||||
if gline.find("%ADD") != -1: # aperture definition
|
if gline.find("%ADD") != -1: # aperture definition
|
||||||
self.aperture_parse(gline) # adds element to apertures
|
self.aperture_parse(gline) # adds element to apertures
|
||||||
continue
|
continue
|
||||||
|
|
||||||
indexstar = gline.find("*")
|
# Interpolation mode change
|
||||||
if gline.find("D") == 0: # Aperture change
|
# Can occur along with coordinates and operation code but
|
||||||
current_aperture = gline[1:indexstar]
|
# sometimes by itself (handled here).
|
||||||
continue
|
# Example: G01*
|
||||||
if gline.find("G54D") == 0: # Aperture change (deprecated)
|
match = self.interp_re.search(gline)
|
||||||
current_aperture = gline[4:indexstar]
|
if match:
|
||||||
continue
|
current_interpolation_mode = int(match.group(1))
|
||||||
|
|
||||||
if gline.find("%FS") != -1: # Format statement
|
|
||||||
indexx = gline.find("X")
|
|
||||||
self.digits = int(gline[indexx + 1])
|
|
||||||
self.fraction = int(gline[indexx + 2])
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Tool/aperture change
|
||||||
|
# Example: D12*
|
||||||
|
match = self.tool_re.search(gline)
|
||||||
|
if match:
|
||||||
|
current_aperture = match.group(1)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# indexstar = gline.find("*")
|
||||||
|
# if gline.find("D") == 0: # Aperture change
|
||||||
|
# current_aperture = gline[1:indexstar]
|
||||||
|
# continue
|
||||||
|
# if gline.find("G54D") == 0: # Aperture change (deprecated)
|
||||||
|
# current_aperture = gline[4:indexstar]
|
||||||
|
# continue
|
||||||
|
|
||||||
|
# Number format
|
||||||
|
# TODO: This is ignoring most of the format. Implement the rest.
|
||||||
|
match = self.fmt_re.search(gline)
|
||||||
|
if match:
|
||||||
|
self.int_digits = int(match.group(3))
|
||||||
|
self.frac_digits = int(match.group(4))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# if gline.find("%FS") != -1: # Format statement
|
||||||
|
# indexx = gline.find("X")
|
||||||
|
# self.int_digits = int(gline[indexx + 1])
|
||||||
|
# self.frac_digits = int(gline[indexx + 2])
|
||||||
|
# continue
|
||||||
|
|
||||||
# Mode (IN/MM)
|
# Mode (IN/MM)
|
||||||
match = mode_re.search(gline)
|
match = self.mode_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
self.units = match.group(1)
|
self.units = match.group(1)
|
||||||
continue
|
continue
|
||||||
@@ -452,7 +603,12 @@ class Gerber (Geometry):
|
|||||||
# 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})
|
||||||
|
|
||||||
|
# if len(path) > 1:
|
||||||
|
# # EOF, create shapely LineString if something still in path
|
||||||
|
# self.paths.append({"linestring": LineString(path),
|
||||||
|
# "aperture": current_aperture})
|
||||||
|
|
||||||
def do_flashes(self):
|
def do_flashes(self):
|
||||||
"""
|
"""
|
||||||
Creates geometry for Gerber flashes (aperture on a single point).
|
Creates geometry for Gerber flashes (aperture on a single point).
|
||||||
@@ -1133,19 +1289,22 @@ def get_bounds(geometry_set):
|
|||||||
def arc(center, radius, start, stop, direction, steps_per_circ):
|
def arc(center, radius, start, stop, direction, steps_per_circ):
|
||||||
"""
|
"""
|
||||||
Creates a Shapely.LineString for the specified arc.
|
Creates a Shapely.LineString for the specified arc.
|
||||||
@param center: Coordinates of the center [x, y]
|
|
||||||
@type center: list
|
:param center: Coordinates of the center [x, y]
|
||||||
@param radius: Radius of the arc.
|
:type center: list
|
||||||
@type radius: float
|
:param radius: Radius of the arc.
|
||||||
@param start: Starting angle in radians
|
:type radius: float
|
||||||
@type start: float
|
:param start: Starting angle in radians
|
||||||
@param stop: End angle in radians
|
:type start: float
|
||||||
@type stop: float
|
:param stop: End angle in radians
|
||||||
@param direction: Orientation of the arc, "CW" or "CCW"
|
:type stop: float
|
||||||
@type direction: string
|
:param direction: Orientation of the arc, "CW" or "CCW"
|
||||||
@param steps_per_circ: Number of straight line segments to
|
:type direction: string
|
||||||
|
:param steps_per_circ: Number of straight line segments to
|
||||||
represent a circle.
|
represent a circle.
|
||||||
@type steps_per_circ: int
|
:type steps_per_circ: int
|
||||||
|
:return: The desired arc.
|
||||||
|
:rtype: Shapely.LineString
|
||||||
"""
|
"""
|
||||||
da_sign = {"cw": -1.0, "ccw": 1.0}
|
da_sign = {"cw": -1.0, "ccw": 1.0}
|
||||||
points = []
|
points = []
|
||||||
@@ -1170,14 +1329,16 @@ def clear_poly(poly, tooldia, overlap=0.1):
|
|||||||
Creates a list of Shapely geometry objects covering the inside
|
Creates a list of Shapely geometry objects covering the inside
|
||||||
of a Shapely.Polygon. Use for removing all the copper in a region
|
of a Shapely.Polygon. Use for removing all the copper in a region
|
||||||
or bed flattening.
|
or bed flattening.
|
||||||
@param poly: Target polygon
|
|
||||||
@type poly: Shapely.Polygon
|
:param poly: Target polygon
|
||||||
@param tooldia: Diameter of the tool
|
:type poly: Shapely.Polygon
|
||||||
@type tooldia: float
|
:param tooldia: Diameter of the tool
|
||||||
@param overlap: Fraction of the tool diameter to overlap
|
:type tooldia: float
|
||||||
|
:param overlap: Fraction of the tool diameter to overlap
|
||||||
in each pass.
|
in each pass.
|
||||||
@type overlap: float
|
:type overlap: float
|
||||||
@return list of Shapely.Polygon
|
:return: list of Shapely.Polygon
|
||||||
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
poly_cuts = [poly.buffer(-tooldia/2.0)]
|
poly_cuts = [poly.buffer(-tooldia/2.0)]
|
||||||
while True:
|
while True:
|
||||||
@@ -1251,11 +1412,33 @@ def plotg(geo):
|
|||||||
print "Cannot plot:", str(type(g))
|
print "Cannot plot:", str(type(g))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
def parse_gerber_number(strnumber, frac_digits):
|
||||||
|
"""
|
||||||
|
Parse a single number of Gerber coordinates.
|
||||||
|
|
||||||
############### cam.py ####################
|
:param strnumber: String containing a number in decimal digits
|
||||||
def coord(gstr, digits, fraction):
|
from a coordinate data block, possibly with a leading sign.
|
||||||
|
:type strnumber: str
|
||||||
|
:param frac_digits: Number of digits used for the fractional
|
||||||
|
part of the number
|
||||||
|
:type frac_digits: int
|
||||||
|
:return: The number in floating point.
|
||||||
|
:rtype: float
|
||||||
|
"""
|
||||||
|
return int(strnumber)*(10**(-frac_digits))
|
||||||
|
|
||||||
|
def parse_gerber_coords(gstr, int_digits, frac_digits):
|
||||||
"""
|
"""
|
||||||
Parse Gerber coordinates
|
Parse Gerber coordinates
|
||||||
|
|
||||||
|
:param gstr: Line of G-Code containing coordinates.
|
||||||
|
:type gstr: str
|
||||||
|
:param int_digits: Number of digits in integer part of a number.
|
||||||
|
:type int_digits: int
|
||||||
|
:param frac_digits: Number of digits in frac_digits part of a number.
|
||||||
|
:type frac_digits: int
|
||||||
|
:return: [x, y] coordinates.
|
||||||
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
global gerbx, gerby
|
global gerbx, gerby
|
||||||
xindex = gstr.find("X")
|
xindex = gstr.find("X")
|
||||||
@@ -1263,14 +1446,13 @@ def coord(gstr, digits, fraction):
|
|||||||
index = gstr.find("D")
|
index = gstr.find("D")
|
||||||
if xindex == -1:
|
if xindex == -1:
|
||||||
x = gerbx
|
x = gerbx
|
||||||
y = int(gstr[(yindex+1):index])*(10**(-fraction))
|
y = int(gstr[(yindex+1):index])*(10**(-frac_digits))
|
||||||
elif yindex == -1:
|
elif yindex == -1:
|
||||||
y = gerby
|
y = gerby
|
||||||
x = int(gstr[(xindex+1):index])*(10**(-fraction))
|
x = int(gstr[(xindex+1):index])*(10**(-frac_digits))
|
||||||
else:
|
else:
|
||||||
x = int(gstr[(xindex+1):yindex])*(10**(-fraction))
|
x = int(gstr[(xindex+1):yindex])*(10**(-frac_digits))
|
||||||
y = int(gstr[(yindex+1):index])*(10**(-fraction))
|
y = int(gstr[(yindex+1):index])*(10**(-frac_digits))
|
||||||
gerbx = x
|
gerbx = x
|
||||||
gerby = y
|
gerby = y
|
||||||
return [x, y]
|
return [x, y]
|
||||||
################ end of cam.py #############
|
|
||||||
|
|||||||
BIN
doc/build/.doctrees/environment.pickle
vendored
BIN
doc/build/.doctrees/environment.pickle
vendored
Binary file not shown.
BIN
doc/build/.doctrees/index.doctree
vendored
BIN
doc/build/.doctrees/index.doctree
vendored
Binary file not shown.
2
doc/build/_sources/index.txt
vendored
2
doc/build/_sources/index.txt
vendored
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Welcome to Cirkuix's documentation!
|
Welcome to FlatCAM's documentation!
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
Contents:
|
Contents:
|
||||||
|
|||||||
4
doc/build/genindex.html
vendored
4
doc/build/genindex.html
vendored
@@ -382,6 +382,10 @@
|
|||||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||||
<td style="width: 33%" valign="top"><dl>
|
<td style="width: 33%" valign="top"><dl>
|
||||||
|
|
||||||
|
<dt><a href="index.html#FlatCAM.App.on_about">on_about() (FlatCAM.App method)</a>
|
||||||
|
</dt>
|
||||||
|
|
||||||
|
|
||||||
<dt><a href="index.html#FlatCAM.App.on_activate_name">on_activate_name() (FlatCAM.App method)</a>
|
<dt><a href="index.html#FlatCAM.App.on_activate_name">on_activate_name() (FlatCAM.App method)</a>
|
||||||
</dt>
|
</dt>
|
||||||
|
|
||||||
|
|||||||
24
doc/build/index.html
vendored
24
doc/build/index.html
vendored
@@ -7,7 +7,7 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
<title>Welcome to Cirkuix’s documentation! — Cirkuix 0.5 documentation</title>
|
<title>Welcome to FlatCAM’s documentation! — Cirkuix 0.5 documentation</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
<ul class="wy-breadcrumbs">
|
<ul class="wy-breadcrumbs">
|
||||||
<li><a href="#">Docs</a> »</li>
|
<li><a href="#">Docs</a> »</li>
|
||||||
|
|
||||||
<li>Welcome to Cirkuix’s documentation!</li>
|
<li>Welcome to FlatCAM’s documentation!</li>
|
||||||
<li class="wy-breadcrumbs-aside">
|
<li class="wy-breadcrumbs-aside">
|
||||||
|
|
||||||
<a href="_sources/index.txt" rel="nofollow"> View page source</a>
|
<a href="_sources/index.txt" rel="nofollow"> View page source</a>
|
||||||
@@ -113,8 +113,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div role="main">
|
<div role="main">
|
||||||
|
|
||||||
<div class="section" id="welcome-to-cirkuix-s-documentation">
|
<div class="section" id="welcome-to-flatcam-s-documentation">
|
||||||
<h1>Welcome to Cirkuix’s documentation!<a class="headerlink" href="#welcome-to-cirkuix-s-documentation" title="Permalink to this headline">¶</a></h1>
|
<h1>Welcome to FlatCAM’s documentation!<a class="headerlink" href="#welcome-to-flatcam-s-documentation" title="Permalink to this headline">¶</a></h1>
|
||||||
<p>Contents:</p>
|
<p>Contents:</p>
|
||||||
<div class="toctree-wrapper compound">
|
<div class="toctree-wrapper compound">
|
||||||
<ul class="simple">
|
<ul class="simple">
|
||||||
@@ -326,6 +326,22 @@ called with 2 parameters: the new object and the App instance.</li>
|
|||||||
</table>
|
</table>
|
||||||
</dd></dl>
|
</dd></dl>
|
||||||
|
|
||||||
|
<dl class="method">
|
||||||
|
<dt id="FlatCAM.App.on_about">
|
||||||
|
<tt class="descname">on_about</tt><big>(</big><em>widget</em><big>)</big><a class="headerlink" href="#FlatCAM.App.on_about" title="Permalink to this definition">¶</a></dt>
|
||||||
|
<dd><p>Opens the ‘About’ dialog box.</p>
|
||||||
|
<table class="docutils field-list" frame="void" rules="none">
|
||||||
|
<col class="field-name" />
|
||||||
|
<col class="field-body" />
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>widget</strong> – Ignored.</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">None</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
<dl class="method">
|
<dl class="method">
|
||||||
<dt id="FlatCAM.App.on_activate_name">
|
<dt id="FlatCAM.App.on_activate_name">
|
||||||
<tt class="descname">on_activate_name</tt><big>(</big><em>entry</em><big>)</big><a class="headerlink" href="#FlatCAM.App.on_activate_name" title="Permalink to this definition">¶</a></dt>
|
<tt class="descname">on_activate_name</tt><big>(</big><em>entry</em><big>)</big><a class="headerlink" href="#FlatCAM.App.on_activate_name" title="Permalink to this definition">¶</a></dt>
|
||||||
|
|||||||
BIN
doc/build/objects.inv
vendored
BIN
doc/build/objects.inv
vendored
Binary file not shown.
2
doc/build/searchindex.js
vendored
2
doc/build/searchindex.js
vendored
File diff suppressed because one or more lines are too long
0
doc/source/test
Normal file
0
doc/source/test
Normal file
Reference in New Issue
Block a user