From 45327552deb95f033e821d35c3a20f207134496a Mon Sep 17 00:00:00 2001 From: Juan Pablo Caram Date: Thu, 20 Nov 2014 21:43:32 -0500 Subject: [PATCH] Gerber support for single quadrant arcs (G74). --- bugs/.doctrees/index.doctree | Bin 5537 -> 5571 bytes bugs/_sources/index.txt | 2 +- bugs/active.html | 10 +++++ bugs/excellonparse.rst | 35 +++++++++++++++ bugs/index.html | 4 ++ bugs/index.rst | 2 +- camlib.py | 82 ++++++++++++++++++++++++++++++++--- 7 files changed, 126 insertions(+), 9 deletions(-) create mode 100644 bugs/excellonparse.rst diff --git a/bugs/.doctrees/index.doctree b/bugs/.doctrees/index.doctree index 0a6e0897e52da4d23d33625a4d911480e7c2fdcb..488009deea8d25dfdbf46673d0c207ab0ec0423f 100644 GIT binary patch delta 2806 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 u9T_X`OKj)j6~Fps@oPn#r + @@ -33,6 +34,9 @@
  • index
  • +
  • + next |
  • previous |
  • @@ -131,6 +135,9 @@ zeros.

    Previous topic

    Welcome to FlatCAM Bugs’s documentation!

    +

    Next topic

    +

    Excellon Parser

    This Page

    • index
    • +
    • + next |
    • previous |
    • diff --git a/bugs/excellonparse.rst b/bugs/excellonparse.rst new file mode 100644 index 00000000..b38dc26a --- /dev/null +++ b/bugs/excellonparse.rst @@ -0,0 +1,35 @@ +Excellon Parser +=============== + +List of test files and their settings +------------------------------------- + +========================== ============== ========= =================== +File Settings Parsed Ok Example +========================== ============== ========= =================== +FlatCAM_Drilling_Test.drl METRIC YES X76324 -> 76mm +Drill_All.drl METRIC NO X019708 -> 1.97mm X +TFTadapter.drl METRIC,TZ YES? X4.572 -> 4.57mm +rfduino dip.drl_ METRIC,TZ NO X236220 -> 23mm X +X-Y CONTROLLER - Drill... METRIC YES X76213 -> 76mm +ucontrllerBoard.drl INCH,TZ YES X1.96572 +holes.drl INCH YES Y+019500 -> 1.95in +BLDC2003Through.drl INCH YES X+023625 -> 2.3in +PlacaReles.drl INCH,TZ YES Y-8200 -> -0.82in +AVR_Transistor_Tester.DRL INCH YES X033000 -> 3.3in +DRL INCH,00.0000 YES/NO* X004759 -> 0.47in +========================== ============== ========= =================== + +(*) The units format is not recognized, thus it is parsed correctly +as long as the project is set for inches already. + +Parser was: + +.. code-block:: python + + def parse_number(self, number_str): + if self.zeros == "L": + match = self.leadingzeros_re.search(number_str) + return float(number_str)/(10**(len(match.group(1)) + len(match.group(2)) - 2)) + else: # Trailing + return float(number_str)/10000 \ No newline at end of file diff --git a/bugs/index.html b/bugs/index.html index 4f5fd045..58fb96a0 100644 --- a/bugs/index.html +++ b/bugs/index.html @@ -54,6 +54,10 @@
    • Drill number parsing
    +
  • Excellon Parser +
  • diff --git a/bugs/index.rst b/bugs/index.rst index 86df8646..5559a9c3 100644 --- a/bugs/index.rst +++ b/bugs/index.rst @@ -12,7 +12,7 @@ Contents: :maxdepth: 2 active - + excellonparse Indices and tables ================== diff --git a/camlib.py b/camlib.py index e642404b..514a3fa5 100644 --- a/camlib.py +++ b/camlib.py @@ -200,7 +200,7 @@ class Geometry(object): log.warning("Solid_geometry not computed yet.") return 0 bounds = self.bounds() - return (bounds[2]-bounds[0], bounds[3]-bounds[1]) + return bounds[2]-bounds[0], bounds[3]-bounds[1] def get_empty_area(self, boundary=None): """ @@ -1164,6 +1164,7 @@ class Gerber (Geometry): # 2-clockwise, 3-counterclockwise match = self.circ_re.search(gline) if match: + arcdir = [None, None, "cw", "ccw"] mode, x, y, i, j, d = match.groups() try: @@ -1224,9 +1225,8 @@ class Gerber (Geometry): if quadrant_mode == 'MULTI': center = [i + current_x, j + current_y] radius = sqrt(i**2 + j**2) - start = arctan2(-j, -i) - stop = arctan2(-center[1] + y, -center[0] + x) - arcdir = [None, None, "cw", "ccw"] + start = arctan2(-j, -i) # Start angle + stop = arctan2(-center[1] + y, -center[0] + x) # Stop angle this_arc = arc(center, radius, start, stop, arcdir[current_interpolation_mode], self.steps_per_circ) @@ -1243,7 +1243,56 @@ class Gerber (Geometry): continue if quadrant_mode == 'SINGLE': - log.warning("Single quadrant arc are not implemented yet. (%d)" % line_num) + #log.warning("Single quadrant arc are not implemented yet. (%d)" % line_num) + + center_candidates = [ + [i + current_x, j + current_y], + [-i + current_x, j + current_y], + [i + current_x, -j + current_y], + [-i + current_x, -j + current_y] + ] + + valid = False + log.debug("I: %f J: %f" % (i, j)) + for center in center_candidates: + radius = sqrt(i**2 + j**2) + + # Make sure radius to start is the same as radius to end. + radius2 = sqrt((center[0] - x)**2 + (center[1] - y)**2) + if radius2 < radius*0.95 or radius2 > radius*1.05: + continue # Not a valid center. + + # Correct i and j and continue as with multi-quadrant. + i = center[0] - current_x + j = center[1] - current_y + + start = arctan2(-j, -i) # Start angle + stop = arctan2(-center[1] + y, -center[0] + x) # Stop angle + angle = abs(arc_angle(start, stop, arcdir[current_interpolation_mode])) + log.debug("ARC START: %f, %f CENTER: %f, %f STOP: %f, %f" % + (current_x, current_y, center[0], center[1], x, y)) + log.debug("START Ang: %f, STOP Ang: %f, DIR: %s, ABS: %.12f <= %.12f: %s" % + (start*180/pi, stop*180/pi, arcdir[current_interpolation_mode], + angle*180/pi, pi/2*180/pi, angle <= (pi+1e-6)/2)) + + if angle <= (pi+1e-6)/2: + log.debug("########## ACCEPTING ARC ############") + this_arc = arc(center, radius, start, stop, + arcdir[current_interpolation_mode], + self.steps_per_circ) + current_x = this_arc[-1][0] + current_y = this_arc[-1][1] + path += this_arc + last_path_aperture = current_aperture + valid = True + break + + if valid: + continue + else: + log.warning("Invalid arc in line %d." % line_num) + + ### Operation code alone # Operation code alone, usually just D03 (Flash) @@ -1786,15 +1835,24 @@ class Excellon(Geometry): :rtype: foat """ if self.zeros == "L": + # With leading zeros, when you type in a coordinate, + # the leading zeros must always be included. Trailing zeros + # are unneeded and may be left off. The CNC-7 will automatically add them. # r'^[-\+]?(0*)(\d*)' # 6 digits are divided by 10^4 # If less than size digits, they are automatically added, - # 5 digits then are divided by 10^3 + # 5 digits then are divided by 10^3 and so on. match = self.leadingzeros_re.search(number_str) return float(number_str)/(10**(len(match.group(1)) + len(match.group(2)) - 2)) else: # Trailing - return float(number_str)/10000 + # You must show all zeros to the right of the number and can omit + # all zeros to the left of the number. The CNC-7 will count the number + # of digits you typed and automatically fill in the missing zeros. + if self.units.lower() == "in": # Inches is 00.0000 + return float(number_str)/10000 + + return float(number_str)/1000 # Metric is 000.000 def create_geometry(self): """ @@ -2621,6 +2679,16 @@ def arc(center, radius, start, stop, direction, steps_per_circ): return points +def arc_angle(start, stop, direction): + if direction == "ccw" and stop <= start: + stop += 2*pi + if direction == "cw" and stop >= start: + stop -= 2*pi + + angle = abs(stop - start) + return angle + + def clear_poly(poly, tooldia, overlap=0.1): """ Creates a list of Shapely geometry objects covering the inside