Просмотр исходного кода

Fixes to gerber parser related to aperture macros and aperture definitions allowed characters in names.

Juan Pablo Caram 11 лет назад
Родитель
Сommit
20c381d510
2 измененных файлов с 316 добавлено и 291 удалено
  1. 315 290
      camlib.py
  2. 1 1
      recent.json

+ 315 - 290
camlib.py

@@ -6,6 +6,8 @@
 # MIT Licence                                              #
 ############################################################
 
+import traceback
+
 from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos
 from matplotlib.figure import Figure
 import re
@@ -31,7 +33,8 @@ import logging
 
 log = logging.getLogger('base2')
 #log.setLevel(logging.DEBUG)
-log.setLevel(logging.WARNING)
+#log.setLevel(logging.WARNING)
+log.setLevel(logging.INFO)
 formatter = logging.Formatter('[%(levelname)s] %(message)s')
 handler = logging.StreamHandler()
 handler.setFormatter(formatter)
@@ -191,6 +194,16 @@ class Geometry(object):
 
 
 class ApertureMacro:
+    """
+    Syntax of aperture macros.
+
+    <AM command>:           AM<Aperture macro name>*<Macro content>
+    <Macro content>:        {{<Variable definition>*}{<Primitive>*}}
+    <Variable definition>:  $K=<Arithmetic expression>
+    <Primitive>:            <Primitive code>,<Modifier>{,<Modifier>}|<Comment>
+    <Modifier>:             $M|< Arithmetic expression>
+    <Comment>:              0 <Text>
+    """
 
     ## Regular expressions
     am1_re = re.compile(r'^%AM([^\*]+)\*(.+)?(%)?$')
@@ -635,11 +648,11 @@ class Gerber (Geometry):
         self.comm_re = re.compile(r'^G0?4(.*)$')
 
         # AD - Aperture definition
-        self.ad_re = re.compile(r'^%ADD(\d\d+)([a-zA-Z0-9]*)(?:,(.*))?\*%$')
+        self.ad_re = re.compile(r'^%ADD(\d\d+)([a-zA-Z_$\.][a-zA-Z0-9_$\.]*)(?:,(.*))?\*%$')
 
         # AM - Aperture Macro
         # Beginning of macro (Ends with *%):
-        self.am_re = re.compile(r'^%AM([a-zA-Z0-9]*)\*')
+        #self.am_re = re.compile(r'^%AM([a-zA-Z0-9]*)\*')
 
         # Tool change
         # May begin with G54 but that is deprecated
@@ -694,7 +707,7 @@ class Gerber (Geometry):
         self.absrel_re = re.compile(r'^G9([01])\*$')
 
         # Aperture macros
-        self.am1_re = re.compile(r'^%AM([^\*]+)\*(.+)?(%)?$')
+        self.am1_re = re.compile(r'^%AM([^\*]+)\*([^%]+)?(%)?$')
         self.am2_re = re.compile(r'(.*)%$')
 
         # TODO: This is bad.
@@ -915,344 +928,356 @@ class Gerber (Geometry):
 
         #### Parsing starts here ####
         line_num = 0
-        for gline in glines:
-            line_num += 1
-
-            ### Cleanup
-            gline = gline.strip(' \r\n')
-
-            ### Aperture Macros
-            # Having this at the beggining will slow things down
-            # but macros can have complicated statements than could
-            # be caught by other ptterns.
-            if current_macro is None:  # No macro started yet
-                match = self.am1_re.search(gline)
-                # Start macro if match, else not an AM, carry on.
-                if match:
-                    current_macro = match.group(1)
-                    self.aperture_macros[current_macro] = ApertureMacro(name=current_macro)
-                    if match.group(2):  # Append
-                        self.aperture_macros[current_macro].append(match.group(2))
-                    if match.group(3):  # Finish macro
+        gline = ""
+        try:
+            for gline in glines:
+                line_num += 1
+
+                ### Cleanup
+                gline = gline.strip(' \r\n')
+
+                ### Aperture Macros
+                # Having this at the beggining will slow things down
+                # but macros can have complicated statements than could
+                # be caught by other ptterns.
+                if current_macro is None:  # No macro started yet
+                    match = self.am1_re.search(gline)
+                    # Start macro if match, else not an AM, carry on.
+                    if match:
+                        log.info("Starting macro. Line %d: %s" % (line_num, gline))
+                        current_macro = match.group(1)
+                        self.aperture_macros[current_macro] = ApertureMacro(name=current_macro)
+                        if match.group(2):  # Append
+                            self.aperture_macros[current_macro].append(match.group(2))
+                        if match.group(3):  # Finish macro
+                            #self.aperture_macros[current_macro].parse_content()
+                            current_macro = None
+                            log.info("Macro complete in 1 line.")
+                        continue
+                else:  # Continue macro
+                    log.info("Continuing macro. Line %d." % line_num)
+                    match = self.am2_re.search(gline)
+                    if match:  # Finish macro
+                        log.info("End of macro. Line %d." % line_num)
+                        self.aperture_macros[current_macro].append(match.group(1))
                         #self.aperture_macros[current_macro].parse_content()
                         current_macro = None
+                    else:  # Append
+                        self.aperture_macros[current_macro].append(gline)
                     continue
-            else:  # Continue macro
-                match = self.am2_re.search(gline)
-                if match:  # Finish macro
-                    self.aperture_macros[current_macro].append(match.group(1))
-                    #self.aperture_macros[current_macro].parse_content()
-                    current_macro = None
-                else:  # Append
-                    self.aperture_macros[current_macro].append(gline)
-                continue
 
-            ### G01 - Linear interpolation plus flashes
-            # Operation code (D0x) missing is deprecated... oh well I will support it.
-            # REGEX: r'^(?:G0?(1))?(?:X(-?\d+))?(?:Y(-?\d+))?(?:D0([123]))?\*$'
-            match = self.lin_re.search(gline)
-            if match:
-                # Dxx alone?
-                # if match.group(1) is None and match.group(2) is None and match.group(3) is None:
-                #     try:
-                #         current_operation_code = int(match.group(4))
-                #     except:
-                #         pass  # A line with just * will match too.
-                #     continue
-                # NOTE: Letting it continue allows it to react to the
-                #       operation code.
-
-                # 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 = int(match.group(4))
-
-                # Pen down: add segment
-                if current_operation_code == 1:
-                    path.append([current_x, current_y])
-                    last_path_aperture = current_aperture
-
-                elif current_operation_code == 2:
-                    if len(path) > 1:
+                ### G01 - Linear interpolation plus flashes
+                # Operation code (D0x) missing is deprecated... oh well I will support it.
+                # REGEX: r'^(?:G0?(1))?(?:X(-?\d+))?(?:Y(-?\d+))?(?:D0([123]))?\*$'
+                match = self.lin_re.search(gline)
+                if match:
+                    # Dxx alone?
+                    # if match.group(1) is None and match.group(2) is None and match.group(3) is None:
+                    #     try:
+                    #         current_operation_code = int(match.group(4))
+                    #     except:
+                    #         pass  # A line with just * will match too.
+                    #     continue
+                    # NOTE: Letting it continue allows it to react to the
+                    #       operation code.
+
+                    # 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 = int(match.group(4))
+
+                    # Pen down: add segment
+                    if current_operation_code == 1:
+                        path.append([current_x, current_y])
+                        last_path_aperture = current_aperture
+
+                    elif current_operation_code == 2:
+                        if len(path) > 1:
+
+                            ## --- BUFFERED ---
+                            if making_region:
+                                geo = Polygon(path)
+                            else:
+                                if last_path_aperture is None:
+                                    log.warning("No aperture defined for curent path. (%d)" % line_num)
+                                width = self.apertures[last_path_aperture]["size"]
+                                geo = LineString(path).buffer(width/2)
+                            poly_buffer.append(geo)
+
+                        path = [[current_x, current_y]]  # Start new path
+
+                    # Flash
+                    elif current_operation_code == 3:
 
-                        ## --- BUFFERED ---
-                        if making_region:
-                            geo = Polygon(path)
-                        else:
-                            if last_path_aperture is None:
-                                log.warning("No aperture defined for curent path. (%d)" % line_num)
-                            width = self.apertures[last_path_aperture]["size"]
-                            geo = LineString(path).buffer(width/2)
-                        poly_buffer.append(geo)
+                        # --- BUFFERED ---
+                        flash = Gerber.create_flash_geometry(Point([current_x, current_y]),
+                                                             self.apertures[current_aperture])
+                        poly_buffer.append(flash)
 
-                    path = [[current_x, current_y]]  # Start new path
+                    continue
 
-                # Flash
-                elif current_operation_code == 3:
+                ### G02/3 - Circular interpolation
+                # 2-clockwise, 3-counterclockwise
+                match = self.circ_re.search(gline)
+                if match:
 
-                    # --- BUFFERED ---
-                    flash = Gerber.create_flash_geometry(Point([current_x, current_y]),
-                                                         self.apertures[current_aperture])
-                    poly_buffer.append(flash)
+                    mode, x, y, i, j, d = match.groups()
+                    try:
+                        x = parse_gerber_number(x, self.frac_digits)
+                    except:
+                        x = current_x
+                    try:
+                        y = parse_gerber_number(y, self.frac_digits)
+                    except:
+                        y = current_y
+                    try:
+                        i = parse_gerber_number(i, self.frac_digits)
+                    except:
+                        i = 0
+                    try:
+                        j = parse_gerber_number(j, self.frac_digits)
+                    except:
+                        j = 0
 
-                continue
+                    if quadrant_mode is None:
+                        log.error("Found arc without preceding quadrant specification G74 or G75. (%d)" % line_num)
+                        log.error(gline)
+                        continue
 
-            ### G02/3 - Circular interpolation
-            # 2-clockwise, 3-counterclockwise
-            match = self.circ_re.search(gline)
-            if match:
+                    if mode is None and current_interpolation_mode not in [2, 3]:
+                        log.error("Found arc without circular interpolation mode defined. (%d)" % line_num)
+                        log.error(gline)
+                        continue
+                    elif mode is not None:
+                        current_interpolation_mode = int(mode)
 
-                mode, x, y, i, j, d = match.groups()
-                try:
-                    x = parse_gerber_number(x, self.frac_digits)
-                except:
-                    x = current_x
-                try:
-                    y = parse_gerber_number(y, self.frac_digits)
-                except:
-                    y = current_y
-                try:
-                    i = parse_gerber_number(i, self.frac_digits)
-                except:
-                    i = 0
-                try:
-                    j = parse_gerber_number(j, self.frac_digits)
-                except:
-                    j = 0
-
-                if quadrant_mode is None:
-                    log.error("Found arc without preceding quadrant specification G74 or G75. (%d)" % line_num)
-                    log.error(gline)
-                    continue
+                    # Set operation code if provided
+                    if d is not None:
+                        current_operation_code = int(d)
 
-                if mode is None and current_interpolation_mode not in [2, 3]:
-                    log.error("Found arc without circular interpolation mode defined. (%d)" % line_num)
-                    log.error(gline)
-                    continue
-                elif mode is not None:
-                    current_interpolation_mode = int(mode)
+                    # Nothing created! Pen Up.
+                    if current_operation_code == 2:
+                        log.warning("Arc with D2. (%d)" % line_num)
+                        if len(path) > 1:
+                            if last_path_aperture is None:
+                                log.warning("No aperture defined for curent path. (%d)" % line_num)
 
-                # Set operation code if provided
-                if d is not None:
-                    current_operation_code = int(d)
+                            # --- BUFFERED ---
+                            width = self.apertures[last_path_aperture]["size"]
+                            buffered = LineString(path).buffer(width/2)
+                            poly_buffer.append(buffered)
 
-                # Nothing created! Pen Up.
-                if current_operation_code == 2:
-                    log.warning("Arc with D2. (%d)" % line_num)
-                    if len(path) > 1:
-                        if last_path_aperture is None:
-                            log.warning("No aperture defined for curent path. (%d)" % line_num)
+                        current_x = x
+                        current_y = y
+                        path = [[current_x, current_y]]  # Start new path
+                        continue
 
-                        # --- BUFFERED ---
-                        width = self.apertures[last_path_aperture]["size"]
-                        buffered = LineString(path).buffer(width/2)
-                        poly_buffer.append(buffered)
+                    # Flash should not happen here
+                    if current_operation_code == 3:
+                        log.error("Trying to flash within arc. (%d)" % line_num)
+                        continue
 
-                    current_x = x
-                    current_y = y
-                    path = [[current_x, current_y]]  # Start new path
-                    continue
+                    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"]
+                        this_arc = arc(center, radius, start, stop,
+                                       arcdir[current_interpolation_mode],
+                                       self.steps_per_circ)
 
-                # Flash should not happen here
-                if current_operation_code == 3:
-                    log.error("Trying to flash within arc. (%d)" % line_num)
-                    continue
+                        # Last point in path is current point
+                        current_x = this_arc[-1][0]
+                        current_y = this_arc[-1][1]
 
-                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"]
-                    this_arc = arc(center, radius, start, stop,
-                                   arcdir[current_interpolation_mode],
-                                   self.steps_per_circ)
+                        # Append
+                        path += this_arc
 
-                    # Last point in path is current point
-                    current_x = this_arc[-1][0]
-                    current_y = this_arc[-1][1]
+                        last_path_aperture = current_aperture
 
-                    # Append
-                    path += this_arc
+                        continue
 
-                    last_path_aperture = current_aperture
+                    if quadrant_mode == 'SINGLE':
+                        log.warning("Single quadrant arc are not implemented yet. (%d)" % line_num)
 
-                    continue
+                ### Operation code alone
+                match = self.opcode_re.search(gline)
+                if match:
+                    current_operation_code = int(match.group(1))
+                    if current_operation_code == 3:
 
-                if quadrant_mode == 'SINGLE':
-                    log.warning("Single quadrant arc are not implemented yet. (%d)" % line_num)
+                        ## --- Buffered ---
+                        flash = Gerber.create_flash_geometry(Point(path[-1]),
+                                                             self.apertures[current_aperture])
+                        poly_buffer.append(flash)
 
-            ### Operation code alone
-            match = self.opcode_re.search(gline)
-            if match:
-                current_operation_code = int(match.group(1))
-                if current_operation_code == 3:
+                    continue
 
-                    ## --- Buffered ---
-                    flash = Gerber.create_flash_geometry(Point(path[-1]),
-                                                         self.apertures[current_aperture])
-                    poly_buffer.append(flash)
+                ### G74/75* - Single or multiple quadrant arcs
+                match = self.quad_re.search(gline)
+                if match:
+                    if match.group(1) == '4':
+                        quadrant_mode = 'SINGLE'
+                    else:
+                        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
 
-            ### G74/75* - Single or multiple quadrant arcs
-            match = self.quad_re.search(gline)
-            if match:
-                if match.group(1) == '4':
-                    quadrant_mode = 'SINGLE'
-                else:
-                    quadrant_mode = 'MULTI'
-                continue
+                        ## --- Buffered ---
+                        width = self.apertures[last_path_aperture]["size"]
+                        geo = LineString(path).buffer(width/2)
+                        poly_buffer.append(geo)
 
-            ### G36* - Begin region
-            if self.regionon_re.search(gline):
-                if len(path) > 1:
-                    # Take care of what is left in the path
+                        path = [path[-1]]
+
+                    making_region = True
+                    continue
 
-                    ## --- Buffered ---
-                    width = self.apertures[last_path_aperture]["size"]
-                    geo = LineString(path).buffer(width/2)
-                    poly_buffer.append(geo)
+                ### G37* - End region
+                if self.regionoff_re.search(gline):
+                    making_region = False
+
+                    # Only one path defines region?
+                    # This can happen if D02 happened before G37 and
+                    # is not and error.
+                    if len(path) < 3:
+                        # print "ERROR: Path contains less than 3 points:"
+                        # print path
+                        # print "Line (%d): " % line_num, gline
+                        # path = []
+                        #path = [[current_x, current_y]]
+                        continue
 
-                    path = [path[-1]]
+                    # For regions we may ignore an aperture that is None
+                    # self.regions.append({"polygon": Polygon(path),
+                    #                      "aperture": last_path_aperture})
 
-                making_region = True
-                continue
+                    # --- Buffered ---
+                    region = Polygon(path)
+                    if not region.is_valid:
+                        region = region.buffer(0)
+                    poly_buffer.append(region)
 
-            ### G37* - End region
-            if self.regionoff_re.search(gline):
-                making_region = False
-
-                # Only one path defines region?
-                # This can happen if D02 happened before G37 and
-                # is not and error.
-                if len(path) < 3:
-                    # print "ERROR: Path contains less than 3 points:"
-                    # print path
-                    # print "Line (%d): " % line_num, gline
-                    # path = []
-                    #path = [[current_x, current_y]]
+                    path = [[current_x, current_y]]  # Start new path
                     continue
 
-                # For regions we may ignore an aperture that is None
-                # self.regions.append({"polygon": Polygon(path),
-                #                      "aperture": last_path_aperture})
+                ### Aperture definitions %ADD...
+                match = self.ad_re.search(gline)
+                if match:
+                    log.info("Found aperture definition. Line %d: %s" % (line_num, gline))
+                    self.aperture_parse(match.group(1), match.group(2), match.group(3))
+                    continue
 
-                # --- Buffered ---
-                region = Polygon(path)
-                if not region.is_valid:
-                    region = region.buffer(0)
-                poly_buffer.append(region)
+                ### G01/2/3* - Interpolation mode change
+                # Can occur along with coordinates and operation code but
+                # sometimes by itself (handled here).
+                # Example: G01*
+                match = self.interp_re.search(gline)
+                if match:
+                    current_interpolation_mode = int(match.group(1))
+                    continue
 
-                path = [[current_x, current_y]]  # Start new path
-                continue
-            
-            ### Aperture definitions %ADD...
-            match = self.ad_re.search(gline)
-            if match:
-                self.aperture_parse(match.group(1), match.group(2), match.group(3))
-                continue
+                ### Tool/aperture change
+                # Example: D12*
+                match = self.tool_re.search(gline)
+                if match:
+                    current_aperture = match.group(1)
+                    continue
 
-            ### G01/2/3* - Interpolation mode change
-            # Can occur along with coordinates and operation code but
-            # sometimes by itself (handled here).
-            # Example: G01*
-            match = self.interp_re.search(gline)
-            if match:
-                current_interpolation_mode = int(match.group(1))
-                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):
 
-            ### Tool/aperture change
-            # Example: D12*
-            match = self.tool_re.search(gline)
-            if match:
-                current_aperture = match.group(1)
-                continue
+                        # --- Buffered ----
+                        width = self.apertures[last_path_aperture]["size"]
+                        geo = LineString(path).buffer(width/2)
+                        poly_buffer.append(geo)
 
-            ### Polarity change
-            # Example: %LPD*% or %LPC*%
-            match = self.lpol_re.search(gline)
-            if match:
-                if len(path) > 1 and current_polarity != match.group(1):
+                        path = [path[-1]]
 
-                    # --- Buffered ----
-                    width = self.apertures[last_path_aperture]["size"]
-                    geo = LineString(path).buffer(width/2)
-                    poly_buffer.append(geo)
+                    # --- Apply buffer ---
+                    if current_polarity == 'D':
+                        self.solid_geometry = self.solid_geometry.union(cascaded_union(poly_buffer))
+                    else:
+                        self.solid_geometry = self.solid_geometry.difference(cascaded_union(poly_buffer))
+                    poly_buffer = []
 
-                    path = [path[-1]]
+                    current_polarity = match.group(1)
+                    continue
 
-                # --- Apply buffer ---
-                if current_polarity == 'D':
-                    self.solid_geometry = self.solid_geometry.union(cascaded_union(poly_buffer))
-                else:
-                    self.solid_geometry = self.solid_geometry.difference(cascaded_union(poly_buffer))
-                poly_buffer = []
+                ### Number format
+                # Example: %FSLAX24Y24*%
+                # TODO: This is ignoring most of the format. Implement the rest.
+                match = self.fmt_re.search(gline)
+                if match:
+                    absolute = {'A': True, 'I': False}
+                    self.int_digits = int(match.group(3))
+                    self.frac_digits = int(match.group(4))
+                    continue
 
-                current_polarity = match.group(1)
-                continue
+                ### Mode (IN/MM)
+                # Example: %MOIN*%
+                match = self.mode_re.search(gline)
+                if match:
+                    self.units = match.group(1)
+                    continue
 
-            ### Number format
-            # Example: %FSLAX24Y24*%
-            # TODO: This is ignoring most of the format. Implement the rest.
-            match = self.fmt_re.search(gline)
-            if match:
-                absolute = {'A': True, 'I': False}
-                self.int_digits = int(match.group(3))
-                self.frac_digits = int(match.group(4))
-                continue
+                ### Units (G70/1) OBSOLETE
+                match = self.units_re.search(gline)
+                if match:
+                    self.units = {'0': 'IN', '1': 'MM'}[match.group(1)]
+                    continue
 
-            ### Mode (IN/MM)
-            # Example: %MOIN*%
-            match = self.mode_re.search(gline)
-            if match:
-                self.units = match.group(1)
-                continue
+                ### Absolute/relative coordinates G90/1 OBSOLETE
+                match = self.absrel_re.search(gline)
+                if match:
+                    absolute = {'0': True, '1': False}[match.group(1)]
+                    continue
 
-            ### Units (G70/1) OBSOLETE
-            match = self.units_re.search(gline)
-            if match:
-                self.units = {'0': 'IN', '1': 'MM'}[match.group(1)]
-                continue
+                #### Ignored lines
+                ## Comments
+                match = self.comm_re.search(gline)
+                if match:
+                    continue
 
-            ### Absolute/relative coordinates G90/1 OBSOLETE
-            match = self.absrel_re.search(gline)
-            if match:
-                absolute = {'0': True, '1': False}[match.group(1)]
-                continue
+                ## EOF
+                match = self.eof_re.search(gline)
+                if match:
+                    continue
 
-            #### Ignored lines
-            ## Comments
-            match = self.comm_re.search(gline)
-            if match:
-                continue
+                ### Line did not match any pattern. Warn user.
+                log.warning("Line ignored (%d): %s" % (line_num, gline))
 
-            ## EOF
-            match = self.eof_re.search(gline)
-            if match:
-                continue
+            if len(path) > 1:
+                # EOF, create shapely LineString if something still in path
 
-            ### Line did not match any pattern. Warn user.
-            log.warning("Line ignored (%d): %s" % (line_num, gline))
-        
-        if len(path) > 1:
-            # EOF, create shapely LineString if something still in path
+                ## --- Buffered ---
+                width = self.apertures[last_path_aperture]["size"]
+                geo = LineString(path).buffer(width/2)
+                poly_buffer.append(geo)
 
-            ## --- Buffered ---
-            width = self.apertures[last_path_aperture]["size"]
-            geo = LineString(path).buffer(width/2)
-            poly_buffer.append(geo)
+            # --- Apply buffer ---
+            if current_polarity == 'D':
+                self.solid_geometry = self.solid_geometry.union(cascaded_union(poly_buffer))
+            else:
+                self.solid_geometry = self.solid_geometry.difference(cascaded_union(poly_buffer))
 
-        # --- Apply buffer ---
-        if current_polarity == 'D':
-            self.solid_geometry = self.solid_geometry.union(cascaded_union(poly_buffer))
-        else:
-            self.solid_geometry = self.solid_geometry.difference(cascaded_union(poly_buffer))
+        except Exception, err:
+            #print traceback.format_exc()
+            log.error("PARSING FAILED. Line %d: %s" % (line_num, gline))
+            raise
 
     @staticmethod
     def create_flash_geometry(location, aperture):

+ 1 - 1
recent.json

@@ -1 +1 @@
-[{"kind": "excellon", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/FlatCam_Drilling_Test/FlatCam_Drilling_Test.drl"}, {"kind": "excellon", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/Excellon_Planck/X-Y CONTROLLER - Drill Data - Through Hole.drl"}, {"kind": "gerber", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/7V-PSU/7V PSU.GTL"}, {"kind": "cncjob", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/output.gcode"}, {"kind": "project", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/project_copy.fcproj"}, {"kind": "project", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/a_project.fcproj"}, {"kind": "project", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/cirkuix/tests/FlatCAM_TestProject.fcproj"}, {"kind": "cncjob", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/cirkuix/tests/FlatCAM_TestGCode.gcode"}, {"kind": "cncjob", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/cirkuix/tests/CBS-B_Cu_ISOLATION_GCODE.ngc"}, {"kind": "excellon", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/cirkuix/tests/FlatCAM_TestDrill.drl"}]
+[{"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/Example1_copper_bottom.gbr"}, {"kind": "gerber", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/7V-PSU.zip"}, {"kind": "gerber", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/Gerbers/AVR_Transistor_Tester_copper_top.GTL"}, {"kind": "gerber", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/XGerber/do-kotle.Bot"}, {"kind": "excellon", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/FlatCam_Drilling_Test/FlatCam_Drilling_Test.drl"}, {"kind": "excellon", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/Excellon_Planck/X-Y CONTROLLER - Drill Data - Through Hole.drl"}, {"kind": "gerber", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/7V-PSU/7V PSU.GTL"}, {"kind": "cncjob", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/output.gcode"}, {"kind": "project", "filename": "C:/Users/jpcaram/Dropbox/CNC/pcbcam/test_files/project_copy.fcproj"}]