From fd1c8afef9bb0a9953962ad33a8663acee1e9408 Mon Sep 17 00:00:00 2001 From: Kamil Sopko Date: Fri, 11 Mar 2016 01:50:12 +0100 Subject: [PATCH] implement basic set of tests for tcl_shell, need to be completed --- FlatCAMApp.py | 412 ++-- tests/gerber_files/detector_contour.gbr | 26 + tests/gerber_files/detector_copper_bottom.gbr | 2146 +++++++++++++++++ tests/gerber_files/detector_copper_top.gbr | 71 + tests/gerber_files/detector_drill.txt | 46 + tests/test_tcl_shell.py | 155 ++ 6 files changed, 2666 insertions(+), 190 deletions(-) create mode 100644 tests/gerber_files/detector_contour.gbr create mode 100644 tests/gerber_files/detector_copper_bottom.gbr create mode 100644 tests/gerber_files/detector_copper_top.gbr create mode 100644 tests/gerber_files/detector_drill.txt create mode 100644 tests/test_tcl_shell.py diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 63e8fb78..7729cb61 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -675,8 +675,19 @@ class App(QtCore.QObject): """ Handles input from the shell. See FlatCAMApp.setup_shell for shell commands. + :param text: + :return: output if there was any + """ + + return self.exec_command_test(self, text, False) + + def exec_command_test(self, text, reraise=True): + """ + Handles input from the shell. See FlatCAMApp.setup_shell for shell commands. + :param text: Input command - :return: None + :param reraise: raise exception and not hide it, used mainly in unittests + :return: output if there was any """ self.report_usage('exec_command') @@ -691,8 +702,10 @@ class App(QtCore.QObject): result = self.tcl.eval("set errorInfo") self.log.error("Exec command Exception: %s" % (result + '\n')) self.shell.append_error('ERROR: ' + result + '\n') - #show error in console and just return - return + #show error in console and just return or in test raise exception + if reraise: + raise e + return result """ Code below is unsused. Saved for later. @@ -2167,85 +2180,96 @@ class App(QtCore.QObject): return 'Ok' - def geocutout(name, *args): - """ + def geocutout(name=None, *args): + ''' + TCL shell command - see help section + Subtract gaps from geometry, this will not create new object - :param name: - :param args: - :return: - """ - a, kwa = h(*args) - types = {'dia': float, - 'gapsize': float, - 'gaps': str} - - # How gaps wil be rendered: - # lr - left + right - # tb - top + bottom - # 4 - left + right +top + bottom - # 2lr - 2*left + 2*right - # 2tb - 2*top + 2*bottom - # 8 - 2*left + 2*right +2*top + 2*bottom - - for key in kwa: - if key not in types: - return 'Unknown parameter: %s' % key - kwa[key] = types[key](kwa[key]) + :param name: name of object + :param args: array of arguments + :return: "Ok" if completed without errors + ''' try: - obj = self.collection.get_by_name(str(name)) - except: - return "Could not retrieve object: %s" % name + a, kwa = h(*args) + types = {'dia': float, + 'gapsize': float, + 'gaps': str} - # Get min and max data for each object as we just cut rectangles across X or Y - xmin, ymin, xmax, ymax = obj.bounds() - px = 0.5 * (xmin + xmax) - py = 0.5 * (ymin + ymax) - lenghtx = (xmax - xmin) - lenghty = (ymax - ymin) - gapsize = kwa['gapsize'] + kwa['dia'] / 2 - - if kwa['gaps'] == '8' or kwa['gaps']=='2lr': - - subtract_rectangle(name, - xmin - gapsize, - py - gapsize + lenghty / 4, - xmax + gapsize, - py + gapsize + lenghty / 4) - subtract_rectangle(name, - xmin-gapsize, - py - gapsize - lenghty / 4, - xmax + gapsize, - py + gapsize - lenghty / 4) - - if kwa['gaps'] == '8' or kwa['gaps']=='2tb': - subtract_rectangle(name, - px - gapsize + lenghtx / 4, - ymin-gapsize, - px + gapsize + lenghtx / 4, - ymax + gapsize) - subtract_rectangle(name, - px - gapsize - lenghtx / 4, - ymin - gapsize, - px + gapsize - lenghtx / 4, - ymax + gapsize) - - if kwa['gaps'] == '4' or kwa['gaps']=='lr': - subtract_rectangle(name, - xmin - gapsize, - py - gapsize, - xmax + gapsize, - py + gapsize) - - if kwa['gaps'] == '4' or kwa['gaps']=='tb': - subtract_rectangle(name, - px - gapsize, - ymin - gapsize, - px + gapsize, - ymax + gapsize) - - return 'Ok' + # How gaps wil be rendered: + # lr - left + right + # tb - top + bottom + # 4 - left + right +top + bottom + # 2lr - 2*left + 2*right + # 2tb - 2*top + 2*bottom + # 8 - 2*left + 2*right +2*top + 2*bottom + + if name is None: + self.raiseTclError('Argument name is missing.') + + for key in kwa: + if key not in types: + self.raiseTclError('Unknown parameter: %s' % key) + try: + kwa[key] = types[key](kwa[key]) + except Exception, e: + self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, str(types[key]))) + + try: + obj = self.collection.get_by_name(str(name)) + except: + self.raiseTclError("Could not retrieve object: %s" % name) + + # Get min and max data for each object as we just cut rectangles across X or Y + xmin, ymin, xmax, ymax = obj.bounds() + px = 0.5 * (xmin + xmax) + py = 0.5 * (ymin + ymax) + lenghtx = (xmax - xmin) + lenghty = (ymax - ymin) + gapsize = kwa['gapsize'] + kwa['dia'] / 2 + + if kwa['gaps'] == '8' or kwa['gaps']=='2lr': + + subtract_rectangle(name, + xmin - gapsize, + py - gapsize + lenghty / 4, + xmax + gapsize, + py + gapsize + lenghty / 4) + subtract_rectangle(name, + xmin-gapsize, + py - gapsize - lenghty / 4, + xmax + gapsize, + py + gapsize - lenghty / 4) + + if kwa['gaps'] == '8' or kwa['gaps']=='2tb': + subtract_rectangle(name, + px - gapsize + lenghtx / 4, + ymin-gapsize, + px + gapsize + lenghtx / 4, + ymax + gapsize) + subtract_rectangle(name, + px - gapsize - lenghtx / 4, + ymin - gapsize, + px + gapsize - lenghtx / 4, + ymax + gapsize) + + if kwa['gaps'] == '4' or kwa['gaps']=='lr': + subtract_rectangle(name, + xmin - gapsize, + py - gapsize, + xmax + gapsize, + py + gapsize) + + if kwa['gaps'] == '4' or kwa['gaps']=='tb': + subtract_rectangle(name, + px - gapsize, + ymin - gapsize, + px + gapsize, + ymax + gapsize) + + except Exception as unknown: + self.raiseTclUnknownError(unknown) def mirror(name, *args): a, kwa = h(*args) @@ -2519,59 +2543,63 @@ class App(QtCore.QObject): :param args: array of arguments :return: "Ok" if completed without errors ''' - a, kwa = h(*args) - types = {'tools': str, - 'outname': str, - 'drillz': float, - 'travelz': float, - 'feedrate': float, - 'spindlespeed': int, - 'toolchange': int - } - if name is None: - self.raiseTclError('Argument name is missing.') + try: + a, kwa = h(*args) + types = {'tools': str, + 'outname': str, + 'drillz': float, + 'travelz': float, + 'feedrate': float, + 'spindlespeed': int, + 'toolchange': int + } + + if name is None: + self.raiseTclError('Argument name is missing.') + + for key in kwa: + if key not in types: + self.raiseTclError('Unknown parameter: %s' % key) + try: + kwa[key] = types[key](kwa[key]) + except Exception, e: + self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, str(types[key]))) - for key in kwa: - if key not in types: - self.raiseTclError('Unknown parameter: %s' % key) try: - kwa[key] = types[key](kwa[key]) + obj = self.collection.get_by_name(str(name)) + except: + self.raiseTclError("Could not retrieve object: %s" % name) + + if obj is None: + self.raiseTclError('Object not found: %s' % name) + + if not isinstance(obj, FlatCAMExcellon): + self.raiseTclError('Only Excellon objects can be drilled, got %s %s.' % (name, type(obj))) + + try: + # Get the tools from the list + job_name = kwa["outname"] + + # Object initialization function for app.new_object() + def job_init(job_obj, app_obj): + job_obj.z_cut = kwa["drillz"] + job_obj.z_move = kwa["travelz"] + job_obj.feedrate = kwa["feedrate"] + job_obj.spindlespeed = kwa["spindlespeed"] if "spindlespeed" in kwa else None + toolchange = True if "toolchange" in kwa and kwa["toolchange"] == 1 else False + job_obj.generate_from_excellon_by_tool(obj, kwa["tools"], toolchange) + job_obj.gcode_parse() + job_obj.create_geometry() + + obj.app.new_object("cncjob", job_name, job_init) + except Exception, e: - self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, str(types[key]))) + self.raiseTclError("Operation failed: %s" % str(e)) - try: - obj = self.collection.get_by_name(str(name)) - except: - self.raiseTclError("Could not retrieve object: %s" % name) + except Exception as unknown: + self.raiseTclUnknownError(unknown) - if obj is None: - self.raiseTclError('Object not found: %s' % name) - - if not isinstance(obj, FlatCAMExcellon): - self.raiseTclError('Only Excellon objects can be drilled, got %s %s.' % (name, type(obj))) - - try: - # Get the tools from the list - job_name = kwa["outname"] - - # Object initialization function for app.new_object() - def job_init(job_obj, app_obj): - job_obj.z_cut = kwa["drillz"] - job_obj.z_move = kwa["travelz"] - job_obj.feedrate = kwa["feedrate"] - job_obj.spindlespeed = kwa["spindlespeed"] if "spindlespeed" in kwa else None - toolchange = True if "toolchange" in kwa and kwa["toolchange"] == 1 else False - job_obj.generate_from_excellon_by_tool(obj, kwa["tools"], toolchange) - job_obj.gcode_parse() - job_obj.create_geometry() - - obj.app.new_object("cncjob", job_name, job_init) - - except Exception, e: - self.raiseTclError("Operation failed: %s" % str(e)) - - return 'Ok' def millholes(name=None, *args): ''' @@ -2580,48 +2608,51 @@ class App(QtCore.QObject): :param args: array of arguments :return: "Ok" if completed without errors ''' - a, kwa = h(*args) - types = {'tooldia': float, - 'tools': str, - 'outname': str} - if name is None: - self.raiseTclError('Argument name is missing.') + try: + a, kwa = h(*args) + types = {'tooldia': float, + 'tools': str, + 'outname': str} + + if name is None: + self.raiseTclError('Argument name is missing.') + + for key in kwa: + if key not in types: + self.raiseTclError('Unknown parameter: %s' % key) + try: + kwa[key] = types[key](kwa[key]) + except Exception, e: + self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, types[key])) - for key in kwa: - if key not in types: - self.raiseTclError('Unknown parameter: %s' % key) try: - kwa[key] = types[key](kwa[key]) - except Exception, e: - self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, types[key])) + if 'tools' in kwa: + kwa['tools'] = [x.strip() for x in kwa['tools'].split(",")] + except Exception as e: + self.raiseTclError("Bad tools: %s" % str(e)) - try: - if 'tools' in kwa: - kwa['tools'] = [x.strip() for x in kwa['tools'].split(",")] - except Exception as e: - self.raiseTclError("Bad tools: %s" % str(e)) + try: + obj = self.collection.get_by_name(str(name)) + except: + self.raiseTclError("Could not retrieve object: %s" % name) - try: - obj = self.collection.get_by_name(str(name)) - except: - self.raiseTclError("Could not retrieve object: %s" % name) + if obj is None: + self.raiseTclError("Object not found: %s" % name) - if obj is None: - self.raiseTclError("Object not found: %s" % name) + if not isinstance(obj, FlatCAMExcellon): + self.raiseTclError('Only Excellon objects can be mill drilled, got %s %s.' % (name, type(obj))) - if not isinstance(obj, FlatCAMExcellon): - self.raiseTclError('Only Excellon objects can be mill drilled, got %s %s.' % (name, type(obj))) + try: + success, msg = obj.generate_milling(**kwa) + except Exception as e: + self.raiseTclError("Operation failed: %s" % str(e)) - try: - success, msg = obj.generate_milling(**kwa) - except Exception as e: - self.raiseTclError("Operation failed: %s" % str(e)) + if not success: + self.raiseTclError(msg) - if not success: - self.raiseTclError(msg) - - return 'Ok' + except Exception as unknown: + self.raiseTclUnknownError(unknown) def exteriors(name=None, *args): ''' @@ -2630,46 +2661,49 @@ class App(QtCore.QObject): :param args: array of arguments :return: "Ok" if completed without errors ''' - a, kwa = h(*args) - types = {'outname': str} - if name is None: - self.raiseTclError('Argument name is missing.') + try: + a, kwa = h(*args) + types = {'outname': str} + + if name is None: + self.raiseTclError('Argument name is missing.') + + for key in kwa: + if key not in types: + self.raiseTclError('Unknown parameter: %s' % key) + try: + kwa[key] = types[key](kwa[key]) + except Exception, e: + self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, types[key])) - for key in kwa: - if key not in types: - self.raiseTclError('Unknown parameter: %s' % key) try: - kwa[key] = types[key](kwa[key]) - except Exception, e: - self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, types[key])) + obj = self.collection.get_by_name(str(name)) + except: + self.raiseTclError("Could not retrieve object: %s" % name) - try: - obj = self.collection.get_by_name(str(name)) - except: - self.raiseTclError("Could not retrieve object: %s" % name) + if obj is None: + self.raiseTclError("Object not found: %s" % name) - if obj is None: - self.raiseTclError("Object not found: %s" % name) + if not isinstance(obj, Geometry): + self.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj))) - if not isinstance(obj, Geometry): - self.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj))) + def geo_init(geo_obj, app_obj): + geo_obj.solid_geometry = obj_exteriors - def geo_init(geo_obj, app_obj): - geo_obj.solid_geometry = obj_exteriors + if 'outname' in kwa: + outname = kwa['outname'] + else: + outname = name + ".exteriors" - if 'outname' in kwa: - outname = kwa['outname'] - else: - outname = name + ".exteriors" + try: + obj_exteriors = obj.get_exteriors() + self.new_object('geometry', outname, geo_init) + except Exception as e: + self.raiseTclError("Failed: %s" % str(e)) - try: - obj_exteriors = obj.get_exteriors() - self.new_object('geometry', outname, geo_init) - except Exception as e: - self.raiseTclError("Failed: %s" % str(e)) - - return 'Ok' + except Exception as unknown: + self.raiseTclUnknownError(unknown) def interiors(name=None, *args): ''' @@ -2722,8 +2756,6 @@ class App(QtCore.QObject): except Exception as unknown: self.raiseTclUnknownError(unknown) - return 'Ok' - def isolate(name=None, *args): ''' TCL shell command - see help section diff --git a/tests/gerber_files/detector_contour.gbr b/tests/gerber_files/detector_contour.gbr new file mode 100644 index 00000000..93adef01 --- /dev/null +++ b/tests/gerber_files/detector_contour.gbr @@ -0,0 +1,26 @@ +G04 MADE WITH FRITZING* +G04 WWW.FRITZING.ORG* +G04 DOUBLE SIDED* +G04 HOLES PLATED* +G04 CONTOUR ON CENTER OF CONTOUR VECTOR* +%ASAXBY*% +%FSLAX23Y23*% +%MOIN*% +%OFA0B0*% +%SFA1.0B1.0*% +%ADD10R,1.771650X1.181100*% +%ADD11C,0.008000*% +%ADD10C,0.008*% +%LNCONTOUR*% +G90* +G70* +G54D10* +G54D11* +X4Y1177D02* +X1768Y1177D01* +X1768Y4D01* +X4Y4D01* +X4Y1177D01* +D02* +G04 End of contour* +M02* \ No newline at end of file diff --git a/tests/gerber_files/detector_copper_bottom.gbr b/tests/gerber_files/detector_copper_bottom.gbr new file mode 100644 index 00000000..d3bca481 --- /dev/null +++ b/tests/gerber_files/detector_copper_bottom.gbr @@ -0,0 +1,2146 @@ +G04 MADE WITH FRITZING* +G04 WWW.FRITZING.ORG* +G04 DOUBLE SIDED* +G04 HOLES PLATED* +G04 CONTOUR ON CENTER OF CONTOUR VECTOR* +%ASAXBY*% +%FSLAX23Y23*% +%MOIN*% +%OFA0B0*% +%SFA1.0B1.0*% +%ADD10C,0.075000*% +%ADD11C,0.099055*% +%ADD12C,0.078740*% +%ADD13R,0.075000X0.075000*% +%ADD14C,0.048000*% +%ADD15C,0.020000*% +%ADD16R,0.001000X0.001000*% +%LNCOPPER0*% +G90* +G70* +G54D10* +X1149Y872D03* +X1349Y872D03* +X749Y722D03* +X749Y522D03* +X1149Y522D03* +X1449Y522D03* +X1149Y422D03* +X1449Y422D03* +X1149Y322D03* +X1449Y322D03* +X1149Y222D03* +X1449Y222D03* +X949Y472D03* +X949Y72D03* +G54D11* +X749Y972D03* +X599Y972D03* +X349Y322D03* +X349Y472D03* +X349Y672D03* +X349Y822D03* +G54D10* +X699Y122D03* +X699Y322D03* +G54D12* +X699Y222D03* +X949Y972D03* +X749Y622D03* +X1049Y222D03* +X1249Y872D03* +G54D13* +X1149Y872D03* +X1149Y522D03* +G54D14* +X949Y373D02* +X949Y433D01* +D02* +X999Y323D02* +X949Y373D01* +D02* +X1109Y322D02* +X999Y323D01* +D02* +X499Y873D02* +X1109Y872D01* +D02* +X1299Y73D02* +X989Y72D01* +D02* +X1399Y322D02* +X1349Y272D01* +D02* +X1349Y272D02* +X1349Y122D01* +D02* +X1349Y122D02* +X1299Y73D01* +D02* +X1409Y322D02* +X1399Y322D01* +D02* +X909Y72D02* +X749Y73D01* +D02* +X749Y73D02* +X727Y94D01* +D02* +X649Y522D02* +X709Y522D01* +D02* +X599Y473D02* +X649Y522D01* +D02* +X401Y472D02* +X599Y473D01* +D02* +X789Y522D02* +X899Y522D01* +D02* +X709Y722D02* +X599Y722D01* +D02* +X599Y722D02* +X549Y673D01* +D02* +X549Y673D02* +X401Y672D01* +D02* +X1149Y562D02* +X1149Y833D01* +D02* +X499Y972D02* +X499Y873D01* +D02* +X547Y972D02* +X499Y972D01* +D02* +X699Y283D02* +X699Y260D01* +D02* +X749Y562D02* +X749Y584D01* +D02* +X499Y873D02* +X499Y972D01* +D02* +X499Y972D02* +X547Y972D01* +D02* +X401Y823D02* +X449Y823D01* +D02* +X899Y522D02* +X921Y500D01* +D02* +X1309Y872D02* +X1287Y872D01* +D02* +X449Y823D02* +X499Y873D01* +D02* +X1349Y422D02* +X1349Y833D01* +D02* +X1189Y422D02* +X1349Y422D01* +D02* +X1399Y322D02* +X1409Y322D01* +D02* +X1349Y372D02* +X1399Y322D01* +D02* +X1349Y422D02* +X1349Y372D01* +D02* +X1189Y422D02* +X1349Y422D01* +D02* +X801Y972D02* +X911Y972D01* +D02* +X1109Y222D02* +X1087Y222D01* +D02* +X401Y322D02* +X659Y322D01* +D02* +X1399Y972D02* +X987Y972D01* +D02* +X1449Y923D02* +X1399Y972D01* +D02* +X1449Y562D02* +X1449Y923D01* +G54D15* +X776Y695D02* +X721Y695D01* +X721Y750D01* +X776Y750D01* +X776Y695D01* +D02* +X671Y150D02* +X726Y150D01* +X726Y95D01* +X671Y95D01* +X671Y150D01* +D02* +G54D16* +X766Y1112D02* +X769Y1112D01* +X764Y1111D02* +X771Y1111D01* +X763Y1110D02* +X772Y1110D01* +X762Y1109D02* +X772Y1109D01* +X762Y1108D02* +X773Y1108D01* +X762Y1107D02* +X773Y1107D01* +X762Y1106D02* +X773Y1106D01* +X762Y1105D02* +X773Y1105D01* +X762Y1104D02* +X773Y1104D01* +X762Y1103D02* +X773Y1103D01* +X762Y1102D02* +X773Y1102D01* +X762Y1101D02* +X773Y1101D01* +X762Y1100D02* +X773Y1100D01* +X762Y1099D02* +X773Y1099D01* +X762Y1098D02* +X773Y1098D01* +X762Y1097D02* +X773Y1097D01* +X762Y1096D02* +X773Y1096D01* +X762Y1095D02* +X773Y1095D01* +X762Y1094D02* +X773Y1094D01* +X762Y1093D02* +X773Y1093D01* +X762Y1092D02* +X773Y1092D01* +X762Y1091D02* +X773Y1091D01* +X762Y1090D02* +X773Y1090D01* +X762Y1089D02* +X773Y1089D01* +X566Y1088D02* +X618Y1088D01* +X741Y1088D02* +X793Y1088D01* +X565Y1087D02* +X620Y1087D01* +X740Y1087D02* +X795Y1087D01* +X564Y1086D02* +X621Y1086D01* +X739Y1086D02* +X796Y1086D01* +X563Y1085D02* +X621Y1085D01* +X738Y1085D02* +X796Y1085D01* +X563Y1084D02* +X622Y1084D01* +X738Y1084D02* +X796Y1084D01* +X563Y1083D02* +X622Y1083D01* +X738Y1083D02* +X796Y1083D01* +X563Y1082D02* +X622Y1082D01* +X738Y1082D02* +X796Y1082D01* +X563Y1081D02* +X622Y1081D01* +X738Y1081D02* +X796Y1081D01* +X563Y1080D02* +X622Y1080D01* +X738Y1080D02* +X796Y1080D01* +X563Y1079D02* +X622Y1079D01* +X739Y1079D02* +X795Y1079D01* +X563Y1078D02* +X622Y1078D01* +X739Y1078D02* +X795Y1078D01* +X563Y1077D02* +X622Y1077D01* +X741Y1077D02* +X794Y1077D01* +X563Y1076D02* +X622Y1076D01* +X762Y1076D02* +X773Y1076D01* +X563Y1075D02* +X621Y1075D01* +X762Y1075D02* +X773Y1075D01* +X563Y1074D02* +X621Y1074D01* +X762Y1074D02* +X773Y1074D01* +X564Y1073D02* +X620Y1073D01* +X762Y1073D02* +X773Y1073D01* +X565Y1072D02* +X619Y1072D01* +X762Y1072D02* +X773Y1072D01* +X569Y1071D02* +X615Y1071D01* +X762Y1071D02* +X773Y1071D01* +X762Y1070D02* +X773Y1070D01* +X762Y1069D02* +X773Y1069D01* +X762Y1068D02* +X773Y1068D01* +X762Y1067D02* +X773Y1067D01* +X762Y1066D02* +X773Y1066D01* +X762Y1065D02* +X773Y1065D01* +X762Y1064D02* +X773Y1064D01* +X762Y1063D02* +X773Y1063D01* +X762Y1062D02* +X773Y1062D01* +X762Y1061D02* +X773Y1061D01* +X762Y1060D02* +X773Y1060D01* +X762Y1059D02* +X773Y1059D01* +X762Y1058D02* +X773Y1058D01* +X762Y1057D02* +X773Y1057D01* +X762Y1056D02* +X773Y1056D01* +X763Y1055D02* +X772Y1055D01* +X763Y1054D02* +X771Y1054D01* +X765Y1053D02* +X770Y1053D01* +X1661Y878D02* +X1697Y878D01* +X1658Y877D02* +X1698Y877D01* +X1656Y876D02* +X1700Y876D01* +X1653Y875D02* +X1701Y875D01* +X1651Y874D02* +X1701Y874D01* +X1648Y873D02* +X1702Y873D01* +X1645Y872D02* +X1702Y872D01* +X1643Y871D02* +X1702Y871D01* +X1640Y870D02* +X1702Y870D01* +X1638Y869D02* +X1703Y869D01* +X1635Y868D02* +X1702Y868D01* +X1633Y867D02* +X1702Y867D01* +X1630Y866D02* +X1702Y866D01* +X1627Y865D02* +X1701Y865D01* +X1625Y864D02* +X1701Y864D01* +X1622Y863D02* +X1700Y863D01* +X1620Y862D02* +X1699Y862D01* +X1617Y861D02* +X1697Y861D01* +X1615Y860D02* +X1664Y860D01* +X1612Y859D02* +X1661Y859D01* +X1609Y858D02* +X1659Y858D01* +X1607Y857D02* +X1656Y857D01* +X1604Y856D02* +X1653Y856D01* +X1602Y855D02* +X1651Y855D01* +X1599Y854D02* +X1648Y854D01* +X1597Y853D02* +X1646Y853D01* +X1594Y852D02* +X1643Y852D01* +X1592Y851D02* +X1641Y851D01* +X1589Y850D02* +X1638Y850D01* +X1586Y849D02* +X1635Y849D01* +X1584Y848D02* +X1633Y848D01* +X1581Y847D02* +X1630Y847D01* +X1579Y846D02* +X1628Y846D01* +X1576Y845D02* +X1625Y845D01* +X1574Y844D02* +X1623Y844D01* +X1571Y843D02* +X1620Y843D01* +X1569Y842D02* +X1618Y842D01* +X1567Y841D02* +X1615Y841D01* +X1566Y840D02* +X1612Y840D01* +X1565Y839D02* +X1610Y839D01* +X1564Y838D02* +X1607Y838D01* +X1564Y837D02* +X1605Y837D01* +X1563Y836D02* +X1602Y836D01* +X1563Y835D02* +X1600Y835D01* +X1563Y834D02* +X1597Y834D01* +X1563Y833D02* +X1599Y833D01* +X1563Y832D02* +X1601Y832D01* +X1564Y831D02* +X1604Y831D01* +X1564Y830D02* +X1606Y830D01* +X1564Y829D02* +X1609Y829D01* +X1565Y828D02* +X1611Y828D01* +X1566Y827D02* +X1614Y827D01* +X1567Y826D02* +X1616Y826D01* +X1569Y825D02* +X1619Y825D01* +X1572Y824D02* +X1622Y824D01* +X1574Y823D02* +X1624Y823D01* +X1577Y822D02* +X1627Y822D01* +X1580Y821D02* +X1629Y821D01* +X1582Y820D02* +X1632Y820D01* +X1585Y819D02* +X1634Y819D01* +X1587Y818D02* +X1637Y818D01* +X1590Y817D02* +X1639Y817D01* +X1592Y816D02* +X1642Y816D01* +X1595Y815D02* +X1645Y815D01* +X1598Y814D02* +X1647Y814D01* +X1600Y813D02* +X1650Y813D01* +X1603Y812D02* +X1652Y812D01* +X1605Y811D02* +X1655Y811D01* +X1608Y810D02* +X1657Y810D01* +X1610Y809D02* +X1660Y809D01* +X1613Y808D02* +X1662Y808D01* +X1616Y807D02* +X1695Y807D01* +X1618Y806D02* +X1698Y806D01* +X1621Y805D02* +X1699Y805D01* +X1623Y804D02* +X1700Y804D01* +X1626Y803D02* +X1701Y803D01* +X1628Y802D02* +X1702Y802D01* +X1631Y801D02* +X1702Y801D01* +X1634Y800D02* +X1702Y800D01* +X1636Y799D02* +X1702Y799D01* +X1639Y798D02* +X1703Y798D01* +X1641Y797D02* +X1702Y797D01* +X1644Y796D02* +X1702Y796D01* +X1646Y795D02* +X1702Y795D01* +X1649Y794D02* +X1702Y794D01* +X1652Y793D02* +X1701Y793D01* +X1654Y792D02* +X1700Y792D01* +X1657Y791D02* +X1699Y791D01* +X1659Y790D02* +X1698Y790D01* +X1662Y789D02* +X1694Y789D01* +X191Y786D02* +X194Y786D01* +X106Y785D02* +X117Y785D01* +X189Y785D02* +X198Y785D01* +X104Y784D02* +X119Y784D01* +X187Y784D02* +X200Y784D01* +X102Y783D02* +X121Y783D01* +X186Y783D02* +X202Y783D01* +X101Y782D02* +X122Y782D01* +X186Y782D02* +X204Y782D01* +X100Y781D02* +X123Y781D01* +X185Y781D02* +X205Y781D01* +X99Y780D02* +X125Y780D01* +X185Y780D02* +X206Y780D01* +X98Y779D02* +X126Y779D01* +X185Y779D02* +X207Y779D01* +X97Y778D02* +X127Y778D01* +X185Y778D02* +X208Y778D01* +X97Y777D02* +X128Y777D01* +X185Y777D02* +X208Y777D01* +X96Y776D02* +X130Y776D01* +X185Y776D02* +X209Y776D01* +X96Y775D02* +X131Y775D01* +X186Y775D02* +X210Y775D01* +X96Y774D02* +X132Y774D01* +X186Y774D02* +X210Y774D01* +X95Y773D02* +X134Y773D01* +X187Y773D02* +X211Y773D01* +X95Y772D02* +X135Y772D01* +X188Y772D02* +X211Y772D01* +X95Y771D02* +X136Y771D01* +X191Y771D02* +X211Y771D01* +X95Y770D02* +X109Y770D01* +X113Y770D02* +X137Y770D01* +X195Y770D02* +X211Y770D01* +X95Y769D02* +X109Y769D01* +X114Y769D02* +X139Y769D01* +X196Y769D02* +X212Y769D01* +X95Y768D02* +X109Y768D01* +X116Y768D02* +X140Y768D01* +X197Y768D02* +X212Y768D01* +X95Y767D02* +X109Y767D01* +X117Y767D02* +X141Y767D01* +X197Y767D02* +X212Y767D01* +X95Y766D02* +X109Y766D01* +X118Y766D02* +X143Y766D01* +X198Y766D02* +X212Y766D01* +X95Y765D02* +X109Y765D01* +X120Y765D02* +X144Y765D01* +X198Y765D02* +X212Y765D01* +X95Y764D02* +X109Y764D01* +X121Y764D02* +X145Y764D01* +X198Y764D02* +X212Y764D01* +X95Y763D02* +X109Y763D01* +X122Y763D02* +X146Y763D01* +X198Y763D02* +X212Y763D01* +X95Y762D02* +X109Y762D01* +X123Y762D02* +X148Y762D01* +X198Y762D02* +X212Y762D01* +X95Y761D02* +X109Y761D01* +X125Y761D02* +X149Y761D01* +X198Y761D02* +X212Y761D01* +X95Y760D02* +X109Y760D01* +X126Y760D02* +X150Y760D01* +X198Y760D02* +X212Y760D01* +X95Y759D02* +X109Y759D01* +X127Y759D02* +X152Y759D01* +X198Y759D02* +X212Y759D01* +X95Y758D02* +X109Y758D01* +X129Y758D02* +X153Y758D01* +X198Y758D02* +X212Y758D01* +X95Y757D02* +X109Y757D01* +X130Y757D02* +X154Y757D01* +X198Y757D02* +X212Y757D01* +X95Y756D02* +X109Y756D01* +X131Y756D02* +X155Y756D01* +X198Y756D02* +X212Y756D01* +X95Y755D02* +X109Y755D01* +X132Y755D02* +X157Y755D01* +X198Y755D02* +X212Y755D01* +X95Y754D02* +X109Y754D01* +X134Y754D02* +X158Y754D01* +X198Y754D02* +X212Y754D01* +X95Y753D02* +X109Y753D01* +X135Y753D02* +X159Y753D01* +X198Y753D02* +X212Y753D01* +X95Y752D02* +X109Y752D01* +X136Y752D02* +X161Y752D01* +X198Y752D02* +X212Y752D01* +X95Y751D02* +X109Y751D01* +X138Y751D02* +X162Y751D01* +X198Y751D02* +X212Y751D01* +X95Y750D02* +X109Y750D01* +X139Y750D02* +X163Y750D01* +X198Y750D02* +X212Y750D01* +X95Y749D02* +X109Y749D01* +X140Y749D02* +X164Y749D01* +X198Y749D02* +X212Y749D01* +X95Y748D02* +X109Y748D01* +X141Y748D02* +X166Y748D01* +X198Y748D02* +X212Y748D01* +X1569Y748D02* +X1620Y748D01* +X95Y747D02* +X109Y747D01* +X143Y747D02* +X167Y747D01* +X198Y747D02* +X212Y747D01* +X1567Y747D02* +X1622Y747D01* +X95Y746D02* +X109Y746D01* +X144Y746D02* +X168Y746D01* +X198Y746D02* +X212Y746D01* +X1566Y746D02* +X1623Y746D01* +X95Y745D02* +X109Y745D01* +X145Y745D02* +X170Y745D01* +X198Y745D02* +X212Y745D01* +X1565Y745D02* +X1624Y745D01* +X95Y744D02* +X109Y744D01* +X147Y744D02* +X171Y744D01* +X198Y744D02* +X212Y744D01* +X1565Y744D02* +X1625Y744D01* +X95Y743D02* +X109Y743D01* +X148Y743D02* +X172Y743D01* +X198Y743D02* +X212Y743D01* +X1564Y743D02* +X1626Y743D01* +X95Y742D02* +X109Y742D01* +X149Y742D02* +X173Y742D01* +X198Y742D02* +X212Y742D01* +X1564Y742D02* +X1626Y742D01* +X95Y741D02* +X109Y741D01* +X151Y741D02* +X175Y741D01* +X198Y741D02* +X212Y741D01* +X1563Y741D02* +X1626Y741D01* +X95Y740D02* +X109Y740D01* +X152Y740D02* +X176Y740D01* +X198Y740D02* +X212Y740D01* +X1563Y740D02* +X1626Y740D01* +X95Y739D02* +X109Y739D01* +X153Y739D02* +X177Y739D01* +X198Y739D02* +X212Y739D01* +X1563Y739D02* +X1626Y739D01* +X95Y738D02* +X109Y738D01* +X154Y738D02* +X179Y738D01* +X198Y738D02* +X212Y738D01* +X1563Y738D02* +X1626Y738D01* +X95Y737D02* +X109Y737D01* +X156Y737D02* +X180Y737D01* +X198Y737D02* +X212Y737D01* +X1563Y737D02* +X1626Y737D01* +X95Y736D02* +X109Y736D01* +X157Y736D02* +X181Y736D01* +X198Y736D02* +X212Y736D01* +X1563Y736D02* +X1626Y736D01* +X95Y735D02* +X109Y735D01* +X158Y735D02* +X182Y735D01* +X198Y735D02* +X212Y735D01* +X1563Y735D02* +X1626Y735D01* +X95Y734D02* +X109Y734D01* +X160Y734D02* +X184Y734D01* +X198Y734D02* +X212Y734D01* +X1563Y734D02* +X1626Y734D01* +X95Y733D02* +X109Y733D01* +X161Y733D02* +X185Y733D01* +X198Y733D02* +X212Y733D01* +X1563Y733D02* +X1626Y733D01* +X95Y732D02* +X109Y732D01* +X162Y732D02* +X186Y732D01* +X198Y732D02* +X212Y732D01* +X1563Y732D02* +X1626Y732D01* +X95Y731D02* +X109Y731D01* +X163Y731D02* +X188Y731D01* +X198Y731D02* +X212Y731D01* +X1563Y731D02* +X1626Y731D01* +X95Y730D02* +X109Y730D01* +X165Y730D02* +X189Y730D01* +X198Y730D02* +X212Y730D01* +X1563Y730D02* +X1581Y730D01* +X1609Y730D02* +X1626Y730D01* +X95Y729D02* +X110Y729D01* +X166Y729D02* +X190Y729D01* +X198Y729D02* +X212Y729D01* +X1563Y729D02* +X1580Y729D01* +X1609Y729D02* +X1626Y729D01* +X95Y728D02* +X110Y728D01* +X167Y728D02* +X191Y728D01* +X198Y728D02* +X212Y728D01* +X1563Y728D02* +X1580Y728D01* +X1609Y728D02* +X1626Y728D01* +X95Y727D02* +X111Y727D01* +X169Y727D02* +X193Y727D01* +X198Y727D02* +X212Y727D01* +X1563Y727D02* +X1580Y727D01* +X1609Y727D02* +X1626Y727D01* +X96Y726D02* +X114Y726D01* +X170Y726D02* +X194Y726D01* +X196Y726D02* +X212Y726D01* +X1563Y726D02* +X1580Y726D01* +X1609Y726D02* +X1626Y726D01* +X96Y725D02* +X118Y725D01* +X171Y725D02* +X212Y725D01* +X1563Y725D02* +X1580Y725D01* +X1609Y725D02* +X1626Y725D01* +X96Y724D02* +X119Y724D01* +X172Y724D02* +X212Y724D01* +X1563Y724D02* +X1580Y724D01* +X1609Y724D02* +X1626Y724D01* +X97Y723D02* +X120Y723D01* +X174Y723D02* +X211Y723D01* +X1563Y723D02* +X1580Y723D01* +X1609Y723D02* +X1626Y723D01* +X97Y722D02* +X121Y722D01* +X175Y722D02* +X211Y722D01* +X1563Y722D02* +X1580Y722D01* +X1609Y722D02* +X1626Y722D01* +X98Y721D02* +X122Y721D01* +X176Y721D02* +X211Y721D01* +X1563Y721D02* +X1580Y721D01* +X1609Y721D02* +X1626Y721D01* +X98Y720D02* +X122Y720D01* +X178Y720D02* +X210Y720D01* +X1563Y720D02* +X1580Y720D01* +X1609Y720D02* +X1626Y720D01* +X99Y719D02* +X122Y719D01* +X179Y719D02* +X210Y719D01* +X1563Y719D02* +X1580Y719D01* +X1609Y719D02* +X1626Y719D01* +X100Y718D02* +X122Y718D01* +X180Y718D02* +X209Y718D01* +X1563Y718D02* +X1580Y718D01* +X1609Y718D02* +X1626Y718D01* +X101Y717D02* +X122Y717D01* +X181Y717D02* +X208Y717D01* +X1563Y717D02* +X1580Y717D01* +X1609Y717D02* +X1626Y717D01* +X102Y716D02* +X122Y716D01* +X183Y716D02* +X207Y716D01* +X1563Y716D02* +X1580Y716D01* +X1609Y716D02* +X1626Y716D01* +X103Y715D02* +X121Y715D01* +X184Y715D02* +X206Y715D01* +X1563Y715D02* +X1580Y715D01* +X1609Y715D02* +X1626Y715D01* +X104Y714D02* +X121Y714D01* +X185Y714D02* +X205Y714D01* +X1563Y714D02* +X1580Y714D01* +X1609Y714D02* +X1626Y714D01* +X106Y713D02* +X120Y713D01* +X187Y713D02* +X204Y713D01* +X1563Y713D02* +X1580Y713D01* +X1609Y713D02* +X1626Y713D01* +X108Y712D02* +X119Y712D01* +X189Y712D02* +X202Y712D01* +X1563Y712D02* +X1580Y712D01* +X1609Y712D02* +X1626Y712D01* +X112Y711D02* +X117Y711D01* +X192Y711D02* +X198Y711D01* +X1563Y711D02* +X1580Y711D01* +X1609Y711D02* +X1626Y711D01* +X1563Y710D02* +X1580Y710D01* +X1609Y710D02* +X1626Y710D01* +X1563Y709D02* +X1580Y709D01* +X1609Y709D02* +X1626Y709D01* +X1563Y708D02* +X1580Y708D01* +X1609Y708D02* +X1626Y708D01* +X1563Y707D02* +X1580Y707D01* +X1609Y707D02* +X1626Y707D01* +X1563Y706D02* +X1580Y706D01* +X1609Y706D02* +X1626Y706D01* +X1563Y705D02* +X1580Y705D01* +X1609Y705D02* +X1626Y705D01* +X1563Y704D02* +X1580Y704D01* +X1609Y704D02* +X1626Y704D01* +X1563Y703D02* +X1580Y703D01* +X1609Y703D02* +X1626Y703D01* +X1563Y702D02* +X1580Y702D01* +X1609Y702D02* +X1626Y702D01* +X1563Y701D02* +X1580Y701D01* +X1609Y701D02* +X1626Y701D01* +X1563Y700D02* +X1580Y700D01* +X1609Y700D02* +X1626Y700D01* +X1563Y699D02* +X1580Y699D01* +X1609Y699D02* +X1626Y699D01* +X1563Y698D02* +X1580Y698D01* +X1609Y698D02* +X1626Y698D01* +X1563Y697D02* +X1580Y697D01* +X1609Y697D02* +X1626Y697D01* +X1563Y696D02* +X1580Y696D01* +X1609Y696D02* +X1626Y696D01* +X1563Y695D02* +X1580Y695D01* +X1609Y695D02* +X1626Y695D01* +X1563Y694D02* +X1580Y694D01* +X1609Y694D02* +X1626Y694D01* +X1563Y693D02* +X1580Y693D01* +X1609Y693D02* +X1626Y693D01* +X1563Y692D02* +X1580Y692D01* +X1609Y692D02* +X1626Y692D01* +X1563Y691D02* +X1580Y691D01* +X1609Y691D02* +X1626Y691D01* +X1563Y690D02* +X1580Y690D01* +X1609Y690D02* +X1626Y690D01* +X1563Y689D02* +X1580Y689D01* +X1609Y689D02* +X1626Y689D01* +X1563Y688D02* +X1580Y688D01* +X1609Y688D02* +X1626Y688D01* +X1563Y687D02* +X1580Y687D01* +X1609Y687D02* +X1626Y687D01* +X1563Y686D02* +X1580Y686D01* +X1609Y686D02* +X1626Y686D01* +X1563Y685D02* +X1580Y685D01* +X1609Y685D02* +X1626Y685D01* +X1690Y685D02* +X1698Y685D01* +X1563Y684D02* +X1580Y684D01* +X1609Y684D02* +X1626Y684D01* +X1689Y684D02* +X1699Y684D01* +X1563Y683D02* +X1580Y683D01* +X1609Y683D02* +X1626Y683D01* +X1688Y683D02* +X1700Y683D01* +X1563Y682D02* +X1580Y682D01* +X1609Y682D02* +X1626Y682D01* +X1687Y682D02* +X1701Y682D01* +X1563Y681D02* +X1580Y681D01* +X1609Y681D02* +X1626Y681D01* +X1686Y681D02* +X1702Y681D01* +X1563Y680D02* +X1580Y680D01* +X1609Y680D02* +X1626Y680D01* +X1686Y680D02* +X1702Y680D01* +X1563Y679D02* +X1580Y679D01* +X1609Y679D02* +X1626Y679D01* +X1686Y679D02* +X1702Y679D01* +X1563Y678D02* +X1580Y678D01* +X1609Y678D02* +X1626Y678D01* +X1685Y678D02* +X1702Y678D01* +X1563Y677D02* +X1581Y677D01* +X1609Y677D02* +X1627Y677D01* +X1685Y677D02* +X1703Y677D01* +X1563Y676D02* +X1703Y676D01* +X1563Y675D02* +X1703Y675D01* +X1563Y674D02* +X1703Y674D01* +X1563Y673D02* +X1703Y673D01* +X1563Y672D02* +X1703Y672D01* +X1563Y671D02* +X1703Y671D01* +X1563Y670D02* +X1703Y670D01* +X1563Y669D02* +X1703Y669D01* +X1563Y668D02* +X1703Y668D01* +X1563Y667D02* +X1702Y667D01* +X1563Y666D02* +X1702Y666D01* +X1564Y665D02* +X1702Y665D01* +X1564Y664D02* +X1702Y664D01* +X1565Y663D02* +X1701Y663D01* +X1566Y662D02* +X1700Y662D01* +X1567Y661D02* +X1699Y661D01* +X1568Y660D02* +X1698Y660D01* +X1572Y659D02* +X1694Y659D01* +X1623Y618D02* +X1635Y618D01* +X1621Y617D02* +X1637Y617D01* +X1620Y616D02* +X1639Y616D01* +X1619Y615D02* +X1640Y615D01* +X1618Y614D02* +X1640Y614D01* +X1617Y613D02* +X1641Y613D01* +X1617Y612D02* +X1641Y612D01* +X1617Y611D02* +X1641Y611D01* +X1617Y610D02* +X1642Y610D01* +X1617Y609D02* +X1642Y609D01* +X1617Y608D02* +X1642Y608D01* +X1617Y607D02* +X1642Y607D01* +X1617Y606D02* +X1642Y606D01* +X1617Y605D02* +X1642Y605D01* +X1617Y604D02* +X1642Y604D01* +X1617Y603D02* +X1642Y603D01* +X1617Y602D02* +X1642Y602D01* +X1617Y601D02* +X1642Y601D01* +X1617Y600D02* +X1642Y600D01* +X1617Y599D02* +X1642Y599D01* +X1617Y598D02* +X1642Y598D01* +X1617Y597D02* +X1642Y597D01* +X1617Y596D02* +X1642Y596D01* +X1617Y595D02* +X1642Y595D01* +X1617Y594D02* +X1642Y594D01* +X1617Y593D02* +X1642Y593D01* +X1617Y592D02* +X1642Y592D01* +X1617Y591D02* +X1642Y591D01* +X1617Y590D02* +X1642Y590D01* +X1617Y589D02* +X1642Y589D01* +X1617Y588D02* +X1642Y588D01* +X1617Y587D02* +X1642Y587D01* +X1617Y586D02* +X1642Y586D01* +X1617Y585D02* +X1642Y585D01* +X1617Y584D02* +X1642Y584D01* +X1617Y583D02* +X1642Y583D01* +X1617Y582D02* +X1642Y582D01* +X1617Y581D02* +X1642Y581D01* +X1617Y580D02* +X1642Y580D01* +X1617Y579D02* +X1642Y579D01* +X1617Y578D02* +X1642Y578D01* +X1617Y577D02* +X1642Y577D01* +X1617Y576D02* +X1642Y576D01* +X1617Y575D02* +X1642Y575D01* +X1617Y574D02* +X1642Y574D01* +X1617Y573D02* +X1642Y573D01* +X1617Y572D02* +X1642Y572D01* +X1617Y571D02* +X1642Y571D01* +X1617Y570D02* +X1642Y570D01* +X1617Y569D02* +X1642Y569D01* +X1617Y568D02* +X1642Y568D01* +X1617Y567D02* +X1642Y567D01* +X1617Y566D02* +X1642Y566D01* +X1617Y565D02* +X1642Y565D01* +X1617Y564D02* +X1642Y564D01* +X1617Y563D02* +X1642Y563D01* +X1617Y562D02* +X1642Y562D01* +X1617Y561D02* +X1642Y561D01* +X1617Y560D02* +X1642Y560D01* +X1617Y559D02* +X1642Y559D01* +X1617Y558D02* +X1642Y558D01* +X1617Y557D02* +X1642Y557D01* +X1617Y556D02* +X1642Y556D01* +X1617Y555D02* +X1642Y555D01* +X1617Y554D02* +X1642Y554D01* +X1617Y553D02* +X1642Y553D01* +X1617Y552D02* +X1642Y552D01* +X1617Y551D02* +X1642Y551D01* +X1617Y550D02* +X1642Y550D01* +X1617Y549D02* +X1642Y549D01* +X1617Y548D02* +X1642Y548D01* +X1617Y547D02* +X1642Y547D01* +X1617Y546D02* +X1642Y546D01* +X1617Y545D02* +X1642Y545D01* +X1617Y544D02* +X1642Y544D01* +X1617Y543D02* +X1642Y543D01* +X1617Y542D02* +X1642Y542D01* +X1617Y541D02* +X1642Y541D01* +X1617Y540D02* +X1642Y540D01* +X1617Y539D02* +X1642Y539D01* +X1617Y538D02* +X1642Y538D01* +X1617Y537D02* +X1642Y537D01* +X1617Y536D02* +X1641Y536D01* +X1617Y535D02* +X1641Y535D01* +X1618Y534D02* +X1641Y534D01* +X1618Y533D02* +X1640Y533D01* +X1619Y532D02* +X1639Y532D01* +X1620Y531D02* +X1638Y531D01* +X1621Y530D02* +X1637Y530D01* +X1625Y529D02* +X1633Y529D01* +X1627Y488D02* +X1638Y488D01* +X1623Y487D02* +X1643Y487D01* +X1620Y486D02* +X1646Y486D01* +X1617Y485D02* +X1649Y485D01* +X1615Y484D02* +X1651Y484D01* +X1613Y483D02* +X1653Y483D01* +X1611Y482D02* +X1655Y482D01* +X1609Y481D02* +X1657Y481D01* +X1607Y480D02* +X1659Y480D01* +X1605Y479D02* +X1661Y479D01* +X1603Y478D02* +X1663Y478D01* +X1601Y477D02* +X1665Y477D01* +X1599Y476D02* +X1667Y476D01* +X1597Y475D02* +X1669Y475D01* +X1595Y474D02* +X1671Y474D01* +X1593Y473D02* +X1673Y473D01* +X1591Y472D02* +X1675Y472D01* +X1589Y471D02* +X1677Y471D01* +X1587Y470D02* +X1629Y470D01* +X1637Y470D02* +X1679Y470D01* +X1585Y469D02* +X1625Y469D01* +X1641Y469D02* +X1681Y469D01* +X1583Y468D02* +X1622Y468D01* +X1643Y468D02* +X1683Y468D01* +X1581Y467D02* +X1620Y467D01* +X1645Y467D02* +X1685Y467D01* +X1579Y466D02* +X1618Y466D01* +X1647Y466D02* +X1687Y466D01* +X1577Y465D02* +X1616Y465D01* +X1649Y465D02* +X1689Y465D01* +X1575Y464D02* +X1614Y464D01* +X1651Y464D02* +X1690Y464D01* +X1573Y463D02* +X1612Y463D01* +X1653Y463D02* +X1692Y463D01* +X1572Y462D02* +X1611Y462D01* +X1655Y462D02* +X1693Y462D01* +X1571Y461D02* +X1609Y461D01* +X1657Y461D02* +X1694Y461D01* +X1570Y460D02* +X1607Y460D01* +X1659Y460D02* +X1695Y460D01* +X1569Y459D02* +X1605Y459D01* +X1661Y459D02* +X1696Y459D01* +X1569Y458D02* +X1603Y458D01* +X1663Y458D02* +X1697Y458D01* +X1568Y457D02* +X1601Y457D01* +X1665Y457D02* +X1697Y457D01* +X1567Y456D02* +X1599Y456D01* +X1667Y456D02* +X1698Y456D01* +X1567Y455D02* +X1597Y455D01* +X1669Y455D02* +X1699Y455D01* +X1566Y454D02* +X1595Y454D01* +X1671Y454D02* +X1699Y454D01* +X1566Y453D02* +X1593Y453D01* +X1673Y453D02* +X1700Y453D01* +X1565Y452D02* +X1591Y452D01* +X1675Y452D02* +X1700Y452D01* +X1565Y451D02* +X1589Y451D01* +X1677Y451D02* +X1701Y451D01* +X1565Y450D02* +X1587Y450D01* +X1679Y450D02* +X1701Y450D01* +X1564Y449D02* +X1585Y449D01* +X1681Y449D02* +X1701Y449D01* +X1564Y448D02* +X1583Y448D01* +X1682Y448D02* +X1702Y448D01* +X1564Y447D02* +X1582Y447D01* +X1683Y447D02* +X1702Y447D01* +X1564Y446D02* +X1582Y446D01* +X1684Y446D02* +X1702Y446D01* +X1563Y445D02* +X1581Y445D01* +X1685Y445D02* +X1702Y445D01* +X1563Y444D02* +X1581Y444D01* +X1685Y444D02* +X1702Y444D01* +X1563Y443D02* +X1581Y443D01* +X1685Y443D02* +X1702Y443D01* +X1563Y442D02* +X1580Y442D01* +X1685Y442D02* +X1703Y442D01* +X1563Y441D02* +X1580Y441D01* +X1685Y441D02* +X1703Y441D01* +X1563Y440D02* +X1580Y440D01* +X1685Y440D02* +X1703Y440D01* +X1563Y439D02* +X1580Y439D01* +X1685Y439D02* +X1703Y439D01* +X1563Y438D02* +X1580Y438D01* +X1685Y438D02* +X1703Y438D01* +X1563Y437D02* +X1580Y437D01* +X1685Y437D02* +X1703Y437D01* +X1563Y436D02* +X1580Y436D01* +X1685Y436D02* +X1703Y436D01* +X1563Y435D02* +X1581Y435D01* +X1685Y435D02* +X1703Y435D01* +X1563Y434D02* +X1703Y434D01* +X99Y433D02* +X105Y433D01* +X202Y433D02* +X208Y433D01* +X1563Y433D02* +X1703Y433D01* +X98Y432D02* +X106Y432D01* +X200Y432D02* +X209Y432D01* +X1563Y432D02* +X1703Y432D01* +X97Y431D02* +X107Y431D01* +X199Y431D02* +X210Y431D01* +X1563Y431D02* +X1703Y431D01* +X96Y430D02* +X108Y430D01* +X199Y430D02* +X211Y430D01* +X1563Y430D02* +X1703Y430D01* +X95Y429D02* +X109Y429D01* +X198Y429D02* +X211Y429D01* +X1563Y429D02* +X1703Y429D01* +X95Y428D02* +X109Y428D01* +X198Y428D02* +X212Y428D01* +X1563Y428D02* +X1703Y428D01* +X95Y427D02* +X109Y427D01* +X198Y427D02* +X212Y427D01* +X1563Y427D02* +X1703Y427D01* +X95Y426D02* +X109Y426D01* +X198Y426D02* +X212Y426D01* +X1563Y426D02* +X1703Y426D01* +X95Y425D02* +X109Y425D01* +X198Y425D02* +X212Y425D01* +X1563Y425D02* +X1703Y425D01* +X95Y424D02* +X109Y424D01* +X198Y424D02* +X212Y424D01* +X1563Y424D02* +X1703Y424D01* +X95Y423D02* +X109Y423D01* +X198Y423D02* +X212Y423D01* +X1563Y423D02* +X1703Y423D01* +X95Y422D02* +X109Y422D01* +X198Y422D02* +X212Y422D01* +X1563Y422D02* +X1703Y422D01* +X95Y421D02* +X109Y421D01* +X198Y421D02* +X212Y421D01* +X1563Y421D02* +X1703Y421D01* +X95Y420D02* +X109Y420D01* +X198Y420D02* +X212Y420D01* +X1563Y420D02* +X1703Y420D01* +X95Y419D02* +X109Y419D01* +X198Y419D02* +X212Y419D01* +X1563Y419D02* +X1703Y419D01* +X95Y418D02* +X109Y418D01* +X198Y418D02* +X212Y418D01* +X1563Y418D02* +X1703Y418D01* +X95Y417D02* +X109Y417D01* +X198Y417D02* +X212Y417D01* +X1563Y417D02* +X1703Y417D01* +X95Y416D02* +X109Y416D01* +X198Y416D02* +X212Y416D01* +X1563Y416D02* +X1580Y416D01* +X1685Y416D02* +X1703Y416D01* +X95Y415D02* +X109Y415D01* +X198Y415D02* +X212Y415D01* +X1563Y415D02* +X1580Y415D01* +X1685Y415D02* +X1703Y415D01* +X95Y414D02* +X109Y414D01* +X198Y414D02* +X212Y414D01* +X1563Y414D02* +X1580Y414D01* +X1685Y414D02* +X1703Y414D01* +X95Y413D02* +X109Y413D01* +X198Y413D02* +X212Y413D01* +X1563Y413D02* +X1580Y413D01* +X1685Y413D02* +X1703Y413D01* +X95Y412D02* +X109Y412D01* +X198Y412D02* +X212Y412D01* +X1563Y412D02* +X1580Y412D01* +X1685Y412D02* +X1703Y412D01* +X95Y411D02* +X109Y411D01* +X198Y411D02* +X212Y411D01* +X1563Y411D02* +X1580Y411D01* +X1685Y411D02* +X1703Y411D01* +X95Y410D02* +X109Y410D01* +X198Y410D02* +X212Y410D01* +X1563Y410D02* +X1580Y410D01* +X1685Y410D02* +X1703Y410D01* +X95Y409D02* +X109Y409D01* +X198Y409D02* +X212Y409D01* +X1563Y409D02* +X1580Y409D01* +X1685Y409D02* +X1703Y409D01* +X95Y408D02* +X109Y408D01* +X198Y408D02* +X212Y408D01* +X1563Y408D02* +X1580Y408D01* +X1685Y408D02* +X1703Y408D01* +X95Y407D02* +X109Y407D01* +X198Y407D02* +X212Y407D01* +X1563Y407D02* +X1580Y407D01* +X1685Y407D02* +X1702Y407D01* +X95Y406D02* +X109Y406D01* +X198Y406D02* +X212Y406D01* +X1563Y406D02* +X1580Y406D01* +X1686Y406D02* +X1702Y406D01* +X95Y405D02* +X109Y405D01* +X198Y405D02* +X212Y405D01* +X1564Y405D02* +X1580Y405D01* +X1686Y405D02* +X1702Y405D01* +X95Y404D02* +X109Y404D01* +X198Y404D02* +X212Y404D01* +X1564Y404D02* +X1580Y404D01* +X1686Y404D02* +X1702Y404D01* +X95Y403D02* +X109Y403D01* +X198Y403D02* +X212Y403D01* +X1565Y403D02* +X1579Y403D01* +X1687Y403D02* +X1701Y403D01* +X95Y402D02* +X109Y402D01* +X198Y402D02* +X212Y402D01* +X1565Y402D02* +X1578Y402D01* +X1688Y402D02* +X1700Y402D01* +X95Y401D02* +X109Y401D01* +X198Y401D02* +X212Y401D01* +X1567Y401D02* +X1577Y401D01* +X1689Y401D02* +X1699Y401D01* +X95Y400D02* +X109Y400D01* +X198Y400D02* +X212Y400D01* +X1568Y400D02* +X1576Y400D01* +X1690Y400D02* +X1698Y400D01* +X95Y399D02* +X109Y399D01* +X198Y399D02* +X212Y399D01* +X1571Y399D02* +X1573Y399D01* +X1693Y399D02* +X1695Y399D01* +X95Y398D02* +X109Y398D01* +X198Y398D02* +X212Y398D01* +X95Y397D02* +X109Y397D01* +X198Y397D02* +X212Y397D01* +X95Y396D02* +X109Y396D01* +X197Y396D02* +X212Y396D01* +X95Y395D02* +X110Y395D01* +X197Y395D02* +X212Y395D01* +X95Y394D02* +X110Y394D01* +X197Y394D02* +X212Y394D01* +X95Y393D02* +X111Y393D01* +X196Y393D02* +X211Y393D01* +X96Y392D02* +X112Y392D01* +X195Y392D02* +X211Y392D01* +X96Y391D02* +X114Y391D01* +X193Y391D02* +X211Y391D01* +X96Y390D02* +X116Y390D01* +X191Y390D02* +X211Y390D01* +X97Y389D02* +X118Y389D01* +X189Y389D02* +X210Y389D01* +X97Y388D02* +X120Y388D01* +X187Y388D02* +X210Y388D01* +X98Y387D02* +X122Y387D01* +X185Y387D02* +X209Y387D01* +X98Y386D02* +X124Y386D01* +X183Y386D02* +X209Y386D01* +X99Y385D02* +X126Y385D01* +X181Y385D02* +X208Y385D01* +X100Y384D02* +X128Y384D01* +X179Y384D02* +X207Y384D01* +X101Y383D02* +X130Y383D01* +X177Y383D02* +X207Y383D01* +X101Y382D02* +X132Y382D01* +X175Y382D02* +X206Y382D01* +X102Y381D02* +X134Y381D01* +X173Y381D02* +X205Y381D01* +X104Y380D02* +X136Y380D01* +X171Y380D02* +X204Y380D01* +X105Y379D02* +X138Y379D01* +X169Y379D02* +X202Y379D01* +X107Y378D02* +X140Y378D01* +X167Y378D02* +X201Y378D01* +X108Y377D02* +X141Y377D01* +X165Y377D02* +X199Y377D01* +X110Y376D02* +X143Y376D01* +X163Y376D02* +X197Y376D01* +X112Y375D02* +X146Y375D01* +X161Y375D02* +X195Y375D01* +X114Y374D02* +X149Y374D01* +X157Y374D02* +X193Y374D01* +X116Y373D02* +X191Y373D01* +X118Y372D02* +X189Y372D01* +X120Y371D02* +X187Y371D01* +X122Y370D02* +X185Y370D01* +X124Y369D02* +X183Y369D01* +X126Y368D02* +X181Y368D01* +X128Y367D02* +X179Y367D01* +X130Y366D02* +X177Y366D01* +X132Y365D02* +X174Y365D01* +X134Y364D02* +X172Y364D01* +X136Y363D02* +X170Y363D01* +X138Y362D02* +X168Y362D01* +X141Y361D02* +X166Y361D01* +X144Y360D02* +X163Y360D01* +X148Y359D02* +X159Y359D01* +X1569Y358D02* +X1702Y358D01* +X1567Y357D02* +X1703Y357D01* +X1566Y356D02* +X1703Y356D01* +X1565Y355D02* +X1703Y355D01* +X1565Y354D02* +X1703Y354D01* +X1564Y353D02* +X1703Y353D01* +X1564Y352D02* +X1703Y352D01* +X1563Y351D02* +X1703Y351D01* +X1563Y350D02* +X1703Y350D01* +X1563Y349D02* +X1703Y349D01* +X1563Y348D02* +X1703Y348D01* +X1564Y347D02* +X1703Y347D01* +X1564Y346D02* +X1703Y346D01* +X1564Y345D02* +X1703Y345D01* +X1565Y344D02* +X1703Y344D01* +X1566Y343D02* +X1703Y343D01* +X1567Y342D02* +X1703Y342D01* +X1569Y341D02* +X1703Y341D01* +X1678Y340D02* +X1703Y340D01* +X1677Y339D02* +X1703Y339D01* +X1675Y338D02* +X1703Y338D01* +X1674Y337D02* +X1703Y337D01* +X1672Y336D02* +X1703Y336D01* +X1671Y335D02* +X1702Y335D01* +X1670Y334D02* +X1700Y334D01* +X1668Y333D02* +X1699Y333D01* +X1667Y332D02* +X1697Y332D01* +X1665Y331D02* +X1696Y331D01* +X1664Y330D02* +X1694Y330D01* +X1662Y329D02* +X1693Y329D01* +X1661Y328D02* +X1692Y328D01* +X1660Y327D02* +X1690Y327D01* +X1658Y326D02* +X1689Y326D01* +X1657Y325D02* +X1687Y325D01* +X1655Y324D02* +X1686Y324D01* +X1654Y323D02* +X1684Y323D01* +X1645Y322D02* +X1683Y322D01* +X1643Y321D02* +X1682Y321D01* +X1642Y320D02* +X1680Y320D01* +X1641Y319D02* +X1679Y319D01* +X1641Y318D02* +X1677Y318D01* +X1640Y317D02* +X1676Y317D01* +X1640Y316D02* +X1674Y316D01* +X1640Y315D02* +X1673Y315D01* +X1640Y314D02* +X1672Y314D01* +X1640Y313D02* +X1672Y313D01* +X1640Y312D02* +X1673Y312D01* +X1640Y311D02* +X1675Y311D01* +X1640Y310D02* +X1676Y310D01* +X1641Y309D02* +X1678Y309D01* +X1641Y308D02* +X1679Y308D01* +X1642Y307D02* +X1681Y307D01* +X1644Y306D02* +X1682Y306D01* +X1646Y305D02* +X1683Y305D01* +X1654Y304D02* +X1685Y304D01* +X1655Y303D02* +X1686Y303D01* +X1657Y302D02* +X1688Y302D01* +X1658Y301D02* +X1689Y301D01* +X1660Y300D02* +X1691Y300D01* +X1661Y299D02* +X1692Y299D01* +X1663Y298D02* +X1693Y298D01* +X1664Y297D02* +X1695Y297D01* +X1665Y296D02* +X1696Y296D01* +X1667Y295D02* +X1698Y295D01* +X1668Y294D02* +X1699Y294D01* +X1670Y293D02* +X1700Y293D01* +X1671Y292D02* +X1702Y292D01* +X1673Y291D02* +X1703Y291D01* +X1674Y290D02* +X1703Y290D01* +X1675Y289D02* +X1703Y289D01* +X1677Y288D02* +X1703Y288D01* +X1571Y287D02* +X1703Y287D01* +X1568Y286D02* +X1703Y286D01* +X1567Y285D02* +X1703Y285D01* +X1566Y284D02* +X1703Y284D01* +X1565Y283D02* +X1703Y283D01* +X1564Y282D02* +X1703Y282D01* +X1564Y281D02* +X1703Y281D01* +X1563Y280D02* +X1703Y280D01* +X1563Y279D02* +X1703Y279D01* +X1563Y278D02* +X1703Y278D01* +X1563Y277D02* +X1703Y277D01* +X1563Y276D02* +X1703Y276D01* +X1564Y275D02* +X1703Y275D01* +X1564Y274D02* +X1703Y274D01* +X1565Y273D02* +X1703Y273D01* +X1565Y272D02* +X1703Y272D01* +X1567Y271D02* +X1703Y271D01* +X1568Y270D02* +X1703Y270D01* +X1571Y269D02* +X1702Y269D01* +D02* +G04 End of Copper0* +M02* \ No newline at end of file diff --git a/tests/gerber_files/detector_copper_top.gbr b/tests/gerber_files/detector_copper_top.gbr new file mode 100644 index 00000000..52b2e2ae --- /dev/null +++ b/tests/gerber_files/detector_copper_top.gbr @@ -0,0 +1,71 @@ +G04 MADE WITH FRITZING* +G04 WWW.FRITZING.ORG* +G04 DOUBLE SIDED* +G04 HOLES PLATED* +G04 CONTOUR ON CENTER OF CONTOUR VECTOR* +%ASAXBY*% +%FSLAX23Y23*% +%MOIN*% +%OFA0B0*% +%SFA1.0B1.0*% +%ADD10C,0.075000*% +%ADD11C,0.099055*% +%ADD12C,0.078740*% +%ADD13R,0.075000X0.075000*% +%ADD14C,0.024000*% +%ADD15C,0.020000*% +%LNCOPPER1*% +G90* +G70* +G54D10* +X1149Y872D03* +X1349Y872D03* +X749Y722D03* +X749Y522D03* +X1149Y522D03* +X1449Y522D03* +X1149Y422D03* +X1449Y422D03* +X1149Y322D03* +X1449Y322D03* +X1149Y222D03* +X1449Y222D03* +X949Y472D03* +X949Y72D03* +G54D11* +X749Y972D03* +X599Y972D03* +X349Y322D03* +X349Y472D03* +X349Y672D03* +X349Y822D03* +G54D10* +X699Y122D03* +X699Y322D03* +G54D12* +X699Y222D03* +X949Y972D03* +X749Y622D03* +X1049Y222D03* +X1249Y872D03* +G54D13* +X1149Y872D03* +X1149Y522D03* +G54D14* +X952Y946D02* +X1045Y249D01* +G54D15* +X776Y695D02* +X721Y695D01* +X721Y750D01* +X776Y750D01* +X776Y695D01* +D02* +X671Y150D02* +X726Y150D01* +X726Y95D01* +X671Y95D01* +X671Y150D01* +D02* +G04 End of Copper1* +M02* \ No newline at end of file diff --git a/tests/gerber_files/detector_drill.txt b/tests/gerber_files/detector_drill.txt new file mode 100644 index 00000000..c4945b84 --- /dev/null +++ b/tests/gerber_files/detector_drill.txt @@ -0,0 +1,46 @@ +; NON-PLATED HOLES START AT T1 +; THROUGH (PLATED) HOLES START AT T100 +M48 +INCH +T1C0.125984 +T100C0.031496 +T101C0.035000 +T102C0.059055 +% +T1 +X001488Y010223 +X001488Y001223 +X016488Y001223 +X016488Y010223 +T100 +X009488Y009723 +X007488Y006223 +X012488Y008723 +X010488Y002223 +X006988Y002223 +T101 +X014488Y004223 +X006988Y003223 +X013488Y008723 +X011488Y008723 +X007488Y005223 +X014488Y003223 +X014488Y002223 +X011488Y005223 +X009488Y000723 +X011488Y004223 +X006988Y001223 +X009488Y004723 +X007488Y007223 +X011488Y003223 +X014488Y005223 +X011488Y002223 +T102 +X003488Y008223 +X003488Y004723 +X007488Y009723 +X003488Y006723 +X005988Y009723 +X003488Y003223 +T00 +M30 diff --git a/tests/test_tcl_shell.py b/tests/test_tcl_shell.py new file mode 100644 index 00000000..51138b1c --- /dev/null +++ b/tests/test_tcl_shell.py @@ -0,0 +1,155 @@ +import sys +import unittest +from PyQt4 import QtGui +from FlatCAMApp import App +from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMCNCjob, FlatCAMExcellon +from ObjectUI import GerberObjectUI, GeometryObjectUI +from time import sleep +import os +import tempfile + +class TclShellCommandTest(unittest.TestCase): + + gerber_files = 'tests/gerber_files' + copper_bottom_filename = 'detector_copper_bottom.gbr' + copper_top_filename = 'detector_copper_top.gbr' + cutout_filename = 'detector_contour.gbr' + excellon_filename = 'detector_drill.txt' + excellon_name = "excellon" + gerber_top_name = "top" + gerber_bottom_name = "bottom" + gerber_cutout_name = "cutout" + engraver_diameter = 0.3 + cutout_diameter = 3 + drill_diameter = 0.8 + + def setUp(self): + self.app = QtGui.QApplication(sys.argv) + + # Create App, keep app defaults (do not load + # user-defined defaults). + self.fc = App(user_defaults=False) + + def tearDown(self): + del self.fc + del self.app + + def test_set_get_units(self): + + self.fc.exec_command_test('set_sys units IN') + self.fc.exec_command_test('new') + units=self.fc.exec_command_test('get_sys units') + self.assertEquals(units, "IN") + + self.fc.exec_command_test('set_sys units MM') + self.fc.exec_command_test('new') + units=self.fc.exec_command_test('get_sys units') + self.assertEquals(units, "MM") + + def test_gerber_flow(self): + + # open gerber files top, bottom and cutout + + self.fc.exec_command_test('set_sys units MM') + self.fc.exec_command_test('new') + + self.fc.exec_command_test('open_gerber %s/%s -outname %s' % (self.gerber_files, self.copper_top_filename, self.gerber_top_name)) + gerber_top_obj = self.fc.collection.get_by_name(self.gerber_top_name) + self.assertTrue(isinstance(gerber_top_obj, FlatCAMGerber), + "Expected FlatCAMGerber, instead, %s is %s" % + (self.gerber_top_name, type(gerber_top_obj))) + + self.fc.exec_command_test('open_gerber %s/%s -outname %s' % (self.gerber_files, self.copper_bottom_filename, self.gerber_bottom_name)) + gerber_bottom_obj = self.fc.collection.get_by_name(self.gerber_bottom_name) + self.assertTrue(isinstance(gerber_bottom_obj, FlatCAMGerber), + "Expected FlatCAMGerber, instead, %s is %s" % + (self.gerber_bottom_name, type(gerber_bottom_obj))) + + self.fc.exec_command_test('open_gerber %s/%s -outname %s' % (self.gerber_files, self.cutout_filename, self.gerber_cutout_name)) + gerber_cutout_obj = self.fc.collection.get_by_name(self.gerber_cutout_name) + self.assertTrue(isinstance(gerber_cutout_obj, FlatCAMGerber), + "Expected FlatCAMGerber, instead, %s is %s" % + (self.gerber_cutout_name, type(gerber_cutout_obj))) + + # exteriors delete and join geometries for top layer + self.fc.exec_command_test('isolate %s -dia %f' % (self.gerber_cutout_name, self.engraver_diameter)) + self.fc.exec_command_test('exteriors %s -outname %s' % (self.gerber_cutout_name + '_iso', self.gerber_cutout_name + '_iso_exterior')) + self.fc.exec_command_test('delete %s' % (self.gerber_cutout_name + '_iso')) + obj = self.fc.collection.get_by_name(self.gerber_cutout_name + '_iso_exterior') + self.assertTrue(isinstance(obj, FlatCAMGeometry), + "Expected FlatCAMGeometry, instead, %s is %s" % + (self.gerber_cutout_name + '_iso_exterior', type(obj))) + + # mirror bottom gerbers + self.fc.exec_command_test('mirror %s -box %s -axis X' % (self.gerber_bottom_name, self.gerber_cutout_name)) + self.fc.exec_command_test('mirror %s -box %s -axis X' % (self.gerber_cutout_name, self.gerber_cutout_name)) + + # exteriors delete and join geometries for bottom layer + self.fc.exec_command_test('isolate %s -dia %f -outname %s' % (self.gerber_cutout_name, self.engraver_diameter, self.gerber_cutout_name + '_bottom_iso')) + self.fc.exec_command_test('exteriors %s -outname %s' % (self.gerber_cutout_name + '_bottom_iso', self.gerber_cutout_name + '_bottom_iso_exterior')) + self.fc.exec_command_test('delete %s' % (self.gerber_cutout_name + '_bottom_iso')) + obj = self.fc.collection.get_by_name(self.gerber_cutout_name + '_bottom_iso_exterior') + self.assertTrue(isinstance(obj, FlatCAMGeometry), + "Expected FlatCAMGeometry, instead, %s is %s" % + (self.gerber_cutout_name + '_bottom_iso_exterior', type(obj))) + + # at this stage we should have 5 objects + names = self.fc.collection.get_names() + self.assertEqual(len(names), 5, + "Expected 5 objects, found %d" % len(names)) + + # isolate traces + self.fc.exec_command_test('isolate %s -dia %f' % (self.gerber_top_name, self.engraver_diameter)) + self.fc.exec_command_test('isolate %s -dia %f' % (self.gerber_bottom_name, self.engraver_diameter)) + + # join isolated geometries for top and bottom + self.fc.exec_command_test('join_geometries %s %s %s' % (self.gerber_top_name + '_join_iso', self.gerber_top_name + '_iso', self.gerber_cutout_name + '_iso_exterior')) + self.fc.exec_command_test('join_geometries %s %s %s' % (self.gerber_bottom_name + '_join_iso', self.gerber_bottom_name + '_iso', self.gerber_cutout_name + '_bottom_iso_exterior')) + + # at this stage we should have 9 objects + names = self.fc.collection.get_names() + self.assertEqual(len(names), 9, + "Expected 9 objects, found %d" % len(names)) + + # clean unused isolations + self.fc.exec_command_test('delete %s' % (self.gerber_bottom_name + '_iso')) + self.fc.exec_command_test('delete %s' % (self.gerber_top_name + '_iso')) + self.fc.exec_command_test('delete %s' % (self.gerber_cutout_name + '_iso_exterior')) + self.fc.exec_command_test('delete %s' % (self.gerber_cutout_name + '_bottom_iso_exterior')) + + # at this stage we should have 5 objects again + names = self.fc.collection.get_names() + self.assertEqual(len(names), 5, + "Expected 5 objects, found %d" % len(names)) + + # geocutout bottom test (it cuts to same object) + self.fc.exec_command_test('isolate %s -dia %f -outname %s' % (self.gerber_cutout_name, self.cutout_diameter, self.gerber_cutout_name + '_bottom_iso')) + self.fc.exec_command_test('exteriors %s -outname %s' % (self.gerber_cutout_name + '_bottom_iso', self.gerber_cutout_name + '_bottom_iso_exterior')) + self.fc.exec_command_test('delete %s' % (self.gerber_cutout_name + '_bottom_iso')) + obj = self.fc.collection.get_by_name(self.gerber_cutout_name + '_bottom_iso_exterior') + self.assertTrue(isinstance(obj, FlatCAMGeometry), + "Expected FlatCAMGeometry, instead, %s is %s" % + (self.gerber_cutout_name + '_bottom_iso_exterior', type(obj))) + self.fc.exec_command_test('geocutout %s -dia %f -gapsize 0.3 -gaps 4' % (self.gerber_cutout_name + '_bottom_iso_exterior', self.cutout_diameter)) + + # at this stage we should have 6 objects + names = self.fc.collection.get_names() + self.assertEqual(len(names), 6, + "Expected 6 objects, found %d" % len(names)) + + # TODO: tests for tcl + + def test_excellon_flow(self): + + + self.fc.exec_command_test('set_sys units MM') + self.fc.exec_command_test('open_excellon %s/%s -outname %s' % (self.gerber_files, self.excellon_filename, self.excellon_name)) + excellon_obj = self.fc.collection.get_by_name(self.excellon_name) + self.assertTrue(isinstance(excellon_obj, FlatCAMExcellon), + "Expected FlatCAMExcellon, instead, %s is %s" % + (self.excellon_name, type(excellon_obj))) + + # mirror bottom excellon + self.fc.exec_command_test('mirror %s -box %s -axis X' % (self.excellon_name, self.gerber_cutout_name)) + + # TODO: tests for tcl \ No newline at end of file