From 244fcaa5346f4fad819cc2b72857cfb2c472944a Mon Sep 17 00:00:00 2001 From: Hiroshi Murayama Date: Sat, 28 Dec 2019 23:45:33 +0900 Subject: add a function that generate filled gerberdata with representing internal shape by fliping polarity --- README.md | 141 +- examples/inputs/fill.dxf | 2602 -------------------------------- examples/panelize.py | 7 +- gerberex/dxf.py | 282 +++- gerberex/dxf_path.py | 125 +- gerberex/utility.py | 9 +- setup.py | 2 +- tests/data/ref_dxf_metric.dxf | 304 +++- tests/data/ref_dxf_mousebites.dxf | 344 ----- tests/expects/dxf_offset.gtl | 82 +- tests/expects/dxf_rotate.gtl | 82 +- tests/expects/dxf_save_fill.gtl | 71 +- tests/expects/dxf_save_fill_simple.gtl | 78 + tests/expects/dxf_save_line.gtl | 84 +- tests/expects/dxf_save_line.txt | 84 ++ tests/expects/dxf_save_mousebites.gtl | 592 +++++++- tests/expects/dxf_save_mousebites.txt | 592 +++++++- tests/expects/dxf_to_inch.gtl | 82 +- tests/test_dxf.py | 30 +- 19 files changed, 2428 insertions(+), 3165 deletions(-) delete mode 100644 examples/inputs/fill.dxf delete mode 100644 tests/data/ref_dxf_mousebites.dxf create mode 100644 tests/expects/dxf_save_fill_simple.gtl create mode 100644 tests/expects/dxf_save_line.txt diff --git a/README.md b/README.md index 2831672..252de53 100644 --- a/README.md +++ b/README.md @@ -68,96 +68,121 @@ ctx.dump('panelized-board.txt') ``` ## DXF file translation +pcb-tools-extension hsa a function to load a DXF file and handle that as same as RX-274x gerber file or Excellon NC file.
+In this version, Only line, circle, arc, and polyline objects are recognized and are translated to gerber file or NC file. -### PCB Outline -You can also load a dxf file and handle that as same as RX-274x gerber file or Excellon NC file.
-This function is useful to generate outline data of pnanelized PCB boad. +### Two way to tranlate DXF file +Both composition objects, ```GerberComposition``` for RX-274x and ```DrillionComposition``` for Excellon, can accept an object created as result of DXF file loaded. When composition object dump text stream, DXF data tranclate to appropriate format data.
+The object which represent DXF file, can also output translated data directly by ```save``` method. In this case output format is specified by ```filetype``` argument. If ```filetype``` argument is ommited, DXF data is translated to RX-274x gerber data. ```python import gerberex +dxf = gerberex.read('sample.dxf') -dxf = gerberex.read('outline.dxf') -ctx1 = gerberex.GerberComposition() -ctx1.merge(dxf) -ctx2 = gerberex.DrillComposition() -ctx2.merge(dxf) +# translate to RX-274x using composition object +ctx = gerberex.GerberComposition() +ctx.merge(dxf) +ctx.dump('sample.gml') + +# translate to Excellon using composition object +ctx = gerberex.DrillComposition() +ctx.merge(dxf) +ctx.dump('sample.txt') + +# translate to RX-274x directly +dxf.save('sample2.gml') + +# translate to Excellon directly +dxf.save('sample2.txt', filetype=dxf.FT_EXCELLON) ``` -Circle object, Arc object, Line object and Polyline object are supported. Other kind of objects in DXF file are ignored when translating to gerber data. -You can specify line width (default 0). PCB tools extension will translate DXF primitive shape to RX-274x line or arc sequense using circle aperture with diamater as same as specified line width.
+### Generating Rectangle +If you want to arrange simple rectangle for PCB outline, ```gerberex.rectangle()``` is better solution. This generate a object representing a rectangle compatible with DXF file object.
```python import gerberex -dxf = gerberex.read('outline.dxf') -dxf.to_inch() -dxf.width = 0.004 -dxf.write('outline.gml') +outline = gerberex.rectangle(width=100, height=100, units='metric') +outline.write('outline.gml') ``` -If ```FT_EXCELLON``` is specified for ```filetype``` argument of ```write()```, Excellon NC data is generated. In this case, Excellon file consists of routing commands using a specified width drill. +### Drawing Mode +PCB tools extension provide three type of translation method that affects geometric finish. These method are specified a value for ```draw_mode``` attribute, ```DM_LINE```, ```DM_MOUSE_BITES```, or ```DM_FILL```.
+```DM_LINE``` and ```DM_MOUSE_BITES``` are used to translate to both of RX-274x and Excellon, however ```DM_FILL``` is used to translate to only RX-274x. +![Drawing Mode](https://raw.githubusercontent.com/wiki/opiopan/pcb-tools-extension/images/draw_mode.jpg) -```python -import gerberex +- **draw_mode = DM_LINE**
+ All edge expressed as DXF line object, circle object, arc object and plyline objects are translated to line and arc applied a circular aperture in case of RX-274x. That circular aperture r radius is specified by ```width``` attribute. Default value of width is 0.
+ In case of Excellon, DXF objects are translated to routing path command sequence. + This function is useful to generate outline data of pnanelized PCB boad. -dxf = gerberex.read('outline.dxf') -dxf.to_metric() -dxf.width = 0.3 -dxf.write('outline.txt', filetype=dxf.FT_EXCELLON) -``` + ```python + import gerberex + dxf = gerberex.read('outline.dxf') + dxf.to_inch() + dxf.width = 0.004 + dxf.write('outline.gml') + ``` -You can also translate DXF closed shape such as circle to RX-274x polygon fill sequence.
-In order to fill closed shape, ```DM_FILL``` has to be set to ```draw_mode``` property. In this mode, All object except closed shapes listed below are ignored. +- **draw_mode = DM_MOUSE_BITES**
+ mouse bites + If DM_MOUSE_BITES is specified for draw_mode, filled circles are arranged at equal intervals along a paths consisted of DXF line, arc, circle, and plyline objects. + DXF file object in this state can be merged to excellon file also. That means you can arrange mouse bites easily. -- circle -- closed polyline -- closed path which consists of lines and arcs + ```python + import gerberex -NOTE: ```DM_FILL``` can be used only to generate RX-274x data, it cannot be used to generate Excellon data. + ctx = gerberex.DrillComposition() + drill = gerberex.read('drill.txt') + ctx.merge(drill) -```python -import gerberex + dxf = gerberex.read('mousebites.dxf') + dxf.draw_mode = dxf.DM_MOUSE_BITES + dxf.to_metric() + dxf.width = 0.5 + dxf.pitch = 1 + ctx.merge(dxf) -dxf = gerberex.read('outline.dxf') -dxf.draw_mode = dxf.DM_FILL -dxf.write('outline.gml') -``` + ctx.dump('merged_drill.txt') + ``` -If you want to arrange simple rectangle for PCB outline, ```gerberex.rectangle()``` is better solution. This generate a object representing a rectangle compatible with DXF file object.
+- **draw_mode = DM_FILL**
+ You can translate DXF closed shape such as circle to RX-274x polygon fill sequence.
+ In order to fill closed shape, ```DM_FILL``` has to be set to ```draw_mode``` property. In this mode, All object except closed shapes listed below are ignored. -```python -import gerberex + - circle + - closed polyline + - closed path which consists of lines and arcs -outline = gerberex.rectangle(width=100, height=100, units='metric') -outline.write('outline.gml') -``` + If a closed shape is completly included in other closed shape, The inner shape will be draw with reversed polality of container shape as above example image.
-### Mouse bites + I assume there are two typical usecase for this mode.
+ One is to arrange logo design on silk layer. This is superior to other method generating raster image data since image data express as vector data.
+ The other one is generating gerber data represented cropped area of panelized PCB. + By merging rectangle and PCB outline data, generate a file represented cropped area as below, and this kind of data is useful to make PCB image look good a little bit.
+ [This script](https://github.com/opiopan/pcb-tools-extension/blob/master/examples/genimage.py) which generate example image shown below, also uses this technic. -mouse bites + ```python + import gerberex + ctx = gerberex.GerberComposition() -If ```DM_MOUSE_BITES``` is specified for ```draw_mode```, filled circles are arranged at equal intervals along a paths consisted of DXF line, arc, circle, and plyline objects.
-DXF file object in this state can be merged to excellon file also. That means you can arrange mouse bites easily. + rectangle = gerberex.rectangle(width=100, height=100, units='metric') + rectangle.draw_mode = rectangle.DM_FILL + ctx.merge(rectangle) + + outline = gerberex.read('outline.dxf') + outline.draw_mode = outline.DM_FILL + outline.negate_polarity() + ctx.merge(outline) -```python -import gerberex + ctx.dump('cropped_area.gml') + ``` -ctx = gerberex.DrillComposition() -drill = gerberex.read('drill.txt') -ctx.merge(drill) - -dxf = gerberex.read('mousebites.dxf') -dxf.draw_mode = dxf.DM_MOUSE_BITES -dxf.to_metric() -dxf.width = 0.5 -dxf.pitch = 1 -ctx.merge(dxf) + NOTE: ```DM_FILL``` can be used only to generate RX-274x data, it cannot be used to generate Excellon data. -ctx.dump('merged_drill.txt') -``` ## Panelizing Example This example board image is generated by following scripts from [these source data](https://github.com/opiopan/pcb-tools-extension/tree/master/examples/inputs). diff --git a/examples/inputs/fill.dxf b/examples/inputs/fill.dxf deleted file mode 100644 index fdea04b..0000000 --- a/examples/inputs/fill.dxf +++ /dev/null @@ -1,2602 +0,0 @@ -0 -SECTION -2 -HEADER -9 -$INSUNITS -70 -4 -9 -$ACADVER -1 -AC1014 -9 -$HANDSEED -5 -FFFF -0 -ENDSEC -0 -SECTION -2 -TABLES -0 -TABLE -2 -VPORT -5 -8 -100 -AcDbSymbolTable -0 -ENDTAB -0 -TABLE -2 -LTYPE -5 -5 -100 -AcDbSymbolTable -0 -LTYPE -5 -14 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord -2 -BYBLOCK -70 -0 -0 -LTYPE -5 -15 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord -2 -BYLAYER -70 -0 -0 -ENDTAB -0 -TABLE -2 -LAYER -5 -2 -100 -AcDbSymbolTable -70 -2 -0 -LAYER -5 -50 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord -2 -0 -70 -0 -6 -CONTINUOUS -0 -ENDTAB -0 -TABLE -2 -STYLE -5 -3 -100 -AcDbSymbolTable -70 -1 -0 -STYLE -5 -11 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord -2 -STANDARD -70 -0 -0 -ENDTAB -0 -TABLE -2 -VIEW -5 -6 -100 -AcDbSymbolTable -70 -0 -0 -ENDTAB -0 -TABLE -2 -UCS -5 -7 -100 -AcDbSymbolTable -70 -0 -0 -ENDTAB -0 -TABLE -2 -APPID -5 -9 -100 -AcDbSymbolTable -70 -2 -0 -APPID -5 -12 -100 -AcDbSymbolTableRecord -100 -AcDbRegAppTableRecord -2 -ACAD -70 -0 -0 -ENDTAB -0 -TABLE -2 -DIMSTYLE -5 -A -100 -AcDbSymbolTable -70 -1 -0 -ENDTAB -0 -TABLE -2 -BLOCK_RECORD -5 -1 -100 -AcDbSymbolTable -70 -1 -0 -BLOCK_RECORD -5 -1F -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord -2 -*MODEL_SPACE -0 -BLOCK_RECORD -5 -1B -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord -2 -*PAPER_SPACE -0 -ENDTAB -0 -ENDSEC -0 -SECTION -2 -BLOCKS -0 -BLOCK -5 -20 -100 -AcDbEntity -100 -AcDbBlockBegin -2 -*MODEL_SPACE -0 -ENDBLK -5 -21 -100 -AcDbEntity -100 -AcDbBlockEnd -0 -BLOCK -5 -1C -100 -AcDbEntity -100 -AcDbBlockBegin -2 -*PAPER_SPACE -0 -ENDBLK -5 -1D -100 -AcDbEntity -100 -AcDbBlockEnd -0 -ENDSEC -0 -SECTION -2 -ENTITIES -0 -LWPOLYLINE -5 -100 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -6 -70 -1 -43 -0.0 -10 -40 -20 -100 -10 -39.999999999999993 -20 -88.499999999999972 -42 --0.41421356237308982 -10 -38.5 -20 -87 -10 -36.899999999999999 -20 -87 -42 --0.41421356237308982 -10 -35.400000000000006 -20 -88.499999999999972 -10 -35.399999999999999 -20 -100 -0 -LWPOLYLINE -5 -101 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -4 -70 -1 -43 -0.0 -10 -21.25 -20 -63.335000000000001 -42 --0.99999999999999989 -10 -22.450000000000003 -20 -63.335000000000001 -10 -22.450000000000003 -20 -62.034999999999997 -42 --0.99999999999999989 -10 -21.25 -20 -62.034999999999997 -0 -ARC -5 -102 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -21.850000000000001 -20 -63.335000000000001 -30 -0 -40 -0.60000000000000053 -100 -AcDbArc -50 -0 -51 -180 -0 -CIRCLE -5 -103 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -29.950000000000003 -20 -62.685000000000002 -30 -0 -40 -0.59999999999999998 -0 -LWPOLYLINE -5 -104 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -19 -70 -1 -43 -0.0 -10 -22.200000000000003 -20 -60 -42 --0.4142135623730907 -10 -23.700000000000003 -20 -58.5 -10 -23.700000000000003 -20 -55.520659651813133 -42 --0.4142135623730907 -10 -22.200000000000003 -20 -54.020659651813133 -10 -13.5 -20 -54.020659651813133 -42 --0.4142135623730907 -10 -12.000000000000002 -20 -55.520659651813133 -10 -12.000000000000002 -20 -57 -10 -12.000000000000002 -20 -58.5 -42 --0.4142135623730907 -10 -13.5 -20 -60 -10 -13.900000000000002 -20 -60 -10 -15.4 -20 -60 -10 -15.4 -20 -61.5 -10 -15.4 -20 -71.5 -42 --0.41421356237308898 -10 -16.899999999999999 -20 -73 -10 -18.5 -20 -73 -42 --0.41421356237308898 -10 -20 -20 -71.5 -10 -20 -20 -61.5 -10 -20 -20 -60 -10 -21.5 -20 -60 -0 -LWPOLYLINE -5 -105 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -8 -70 -1 -43 -0.0 -10 -22.5 -20 -21.300000000000004 -42 --0.41421356237308982 -10 -21.5 -20 -20.300000000000004 -10 -2.9999999999999982 -20 -20.300000000000004 -42 -0.41421356237309481 -10 -0 -20 -17.300000000000001 -10 -0 -20 -25.500000000000004 -42 -0.41421356237309548 -10 -3.0000000000000004 -20 -22.5 -10 -21.5 -20 -22.5 -42 --0.41421356237308982 -10 -22.5 -20 -21.5 -0 -LWPOLYLINE -5 -106 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -18 -70 -1 -43 -0.0 -10 -43.699999999999989 -20 -55.520659651813126 -42 --0.4142135623730881 -10 -42.199999999999989 -20 -54.020659651813119 -10 -33.199999999999996 -20 -54.020659651813119 -42 --0.4142135623730907 -10 -31.699999999999999 -20 -55.520659651813126 -10 -31.699999999999999 -20 -58.5 -42 --0.4142135623730907 -10 -33.199999999999996 -20 -60 -10 -33.899999999999999 -20 -60 -10 -35.399999999999999 -20 -60 -10 -35.399999999999999 -20 -61.5 -10 -35.399999999999999 -20 -71.5 -42 --0.41421356237308898 -10 -36.899999999999999 -20 -73 -10 -38.5 -20 -73 -42 --0.41421356237308898 -10 -40 -20 -71.5 -10 -40 -20 -61.5 -10 -40 -20 -60 -10 -41.5 -20 -60 -10 -42.199999999999989 -20 -60 -42 --0.4142135623730881 -10 -43.699999999999989 -20 -58.5 -0 -LWPOLYLINE -5 -107 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -6 -70 -1 -43 -0.0 -10 -60.220000000000013 -20 -88.499999999999972 -42 --0.41421356237308982 -10 -58.720000000000013 -20 -87 -10 -56.900000000000006 -20 -87 -42 --0.41421356237308982 -10 -55.400000000000006 -20 -88.499999999999972 -10 -55.399999999999999 -20 -100 -10 -60.220000000000027 -20 -100 -0 -LWPOLYLINE -5 -108 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -9 -70 -1 -43 -0.0 -10 -0 -20 -44 -10 -12.000000000000002 -20 -44 -10 -12.000000000000002 -20 -47.094063415349972 -10 -21 -20 -47.094063415349972 -42 --0.4142135623730907 -10 -22.5 -20 -45.594063415349964 -10 -22.5 -20 -44.300000000000004 -42 --0.4142135623730907 -10 -21 -20 -42.800000000000004 -10 -2.9999999999999982 -20 -42.800000000000004 -42 -0.41421356237309481 -10 -0 -20 -39.800000000000004 -0 -LWPOLYLINE -5 -109 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -54 -70 -1 -43 -0.0 -10 -42.5 -20 -21.5 -10 -42.5 -20 -21.300000000000004 -42 -0.4142135623731002 -10 -43.5 -20 -20.300000000000008 -10 -62 -20 -20.300000000000004 -42 --0.41421356237309509 -10 -65 -20 -17.300000000000001 -10 -65 -20 -16.500250410747213 -42 -0.4142135623730907 -10 -66.5 -20 -15.000250410747213 -10 -66.868642843789601 -20 -15.000250410747213 -42 --0.3348378315883157 -10 -68.310895504208148 -20 -13.912448498461867 -10 -70.46220136370448 -20 -6.3851777718192153 -42 -0.38411426985847918 -10 -72.732501266263071 -20 -4.9651597160810006 -10 -80.234065260223005 -20 -6.2878878457272922 -42 -0.41421356237308843 -10 -81.450804623240941 -20 -8.0255717417460044 -10 -81.446322967315581 -20 -8.0509884755172365 -42 -0.41421356237309825 -10 -79.708639071296886 -20 -9.2677278385351443 -10 -72.519542474307769 -20 -8.0000961415665639 -10 -65.035306016863061 -20 -50.445310296392726 -10 -92.21599999999998 -20 -55.238000000000014 -10 -99.700236457444689 -20 -12.792785845173839 -10 -92.511139860455586 -20 -11.525154148205248 -42 -0.41421356237310253 -10 -91.294400497437664 -20 -9.7874702521865409 -10 -91.298882153363024 -20 -9.7620535184153105 -42 -0.41421356237309104 -10 -93.036566049381747 -20 -8.5453141553973957 -10 -100.00000000000001 -20 -9.7731554392727293 -10 -100.00000000000001 -20 -59.359999999999999 -10 -82.220000000000013 -20 -59.359999999999999 -10 -82.220000000000013 -20 -71.5 -42 -0.41421356237309331 -10 -80.720000000000013 -20 -73 -10 -79.500000000000028 -20 -73 -42 -0.4142135623730881 -10 -78.000000000000028 -20 -71.5 -10 -78.000000000000014 -20 -59.359999999999999 -10 -60.220000000000013 -20 -59.359999999999999 -10 -60.22000000000002 -20 -71.5 -42 -0.4142135623730881 -10 -58.720000000000013 -20 -73 -10 -56.900000000000006 -20 -73 -42 -0.4142135623730881 -10 -55.399999999999999 -20 -71.5 -10 -55.399999999999999 -20 -60 -10 -53.200000000000003 -20 -60 -42 -0.4142135623730881 -10 -51.700000000000003 -20 -58.5 -10 -51.700000000000003 -20 -55.520659651813119 -42 -0.4142135623730881 -10 -53.200000000000003 -20 -54.020659651813112 -10 -58.220000000000013 -20 -54.020659651813119 -42 --0.41421356237309109 -10 -60.220000000000013 -20 -52.020659651813112 -10 -60.220000000000013 -20 -49.094063415349972 -42 --0.41421356237309109 -10 -58.220000000000013 -20 -47.094063415349964 -10 -44 -20 -47.094063415349972 -42 -0.4142135623730881 -10 -42.5 -20 -45.594063415349964 -10 -42.5 -20 -44.300000000000004 -42 -0.4142135623730881 -10 -44 -20 -42.800000000000004 -10 -62 -20 -42.800000000000004 -42 --0.41421356237309509 -10 -65 -20 -39.800000000000004 -10 -65 -20 -25.5 -42 --0.41421356237309509 -10 -62 -20 -22.5 -10 -43.5 -20 -22.499999999999996 -42 -0.4142135623731002 -0 -ARC -5 -110 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -3.0000000000000004 -20 -3.0000000000000004 -30 -0 -40 -3.0000000000000004 -100 -AcDbArc -50 -180 -51 -270 -0 -LINE -5 -111 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -0 -20 -57 -30 -0 -11 -1.9000000000000004 -21 -57 -31 -0 -0 -LINE -5 -112 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -3.4000000000000004 -20 -58.5 -30 -0 -11 -3.4000000000000004 -21 -58.5 -31 -0 -0 -ARC -5 -113 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -1.8999999999999884 -20 -58.499999999999986 -30 -0 -40 -1.500000000000012 -100 -AcDbArc -50 -0 -51 -89.999999999999545 -0 -LWPOLYLINE -5 -114 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -4 -70 -1 -43 -0.0 -10 -2.4500000000000006 -20 -62.034999999999997 -42 --0.99999999999999989 -10 -1.25 -20 -62.034999999999997 -10 -1.2500000000000002 -20 -63.335000000000001 -42 --0.99999999999999989 -10 -2.4500000000000002 -20 -63.335000000000001 -0 -CIRCLE -5 -115 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -9.9499999999999993 -20 -62.685000000000002 -30 -0 -40 -0.59999999999999998 -0 -LWPOLYLINE -5 -116 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -4 -70 -1 -43 -0.0 -10 -12.950000000000001 -20 -63.335000000000001 -42 --0.99999999999999989 -10 -14.150000000000002 -20 -63.335000000000001 -10 -14.150000000000006 -20 -62.034999999999997 -42 --0.99999999999999989 -10 -12.949999999999999 -20 -62.034999999999997 -0 -ARC -5 -117 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -13.550000000000002 -20 -63.335000000000001 -30 -0 -40 -0.60000000000000053 -100 -AcDbArc -50 -0 -51 -180 -0 -ARC -5 -118 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -1.8500000000000003 -20 -63.335000000000001 -30 -0 -40 -0.59999999999999998 -100 -AcDbArc -50 -0 -51 -180 -0 -ARC -5 -119 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -1.8500000000000003 -20 -62.034999999999997 -30 -0 -40 -0.60000000000000031 -100 -AcDbArc -50 --180 -51 -0 -0 -ARC -5 -120 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -13.550000000000002 -20 -62.034999999999997 -30 -0 -40 -0.60000000000000275 -100 -AcDbArc -50 --180 -51 -0 -0 -CIRCLE -5 -121 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -5.4500000000000002 -20 -62.685000000000002 -30 -0 -40 -0.59999999999999998 -0 -LINE -5 -122 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -0 -20 -60 -30 -0 -11 -1.9000000000000004 -21 -60 -31 -0 -0 -LINE -5 -123 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -14.150000000000002 -20 -63.335000000000001 -30 -0 -11 -14.150000000000002 -21 -62.034999999999997 -31 -0 -0 -LINE -5 -124 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -1.25 -20 -62.034999999999997 -30 -0 -11 -1.25 -21 -63.335000000000001 -31 -0 -0 -LINE -5 -125 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -12.949999999999999 -20 -62.034999999999997 -30 -0 -11 -12.950000000000001 -21 -63.335000000000001 -31 -0 -0 -LINE -5 -126 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -2.4500000000000002 -20 -63.335000000000001 -30 -0 -11 -2.4500000000000002 -21 -62.034999999999997 -31 -0 -0 -LWPOLYLINE -5 -127 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -6 -70 -1 -43 -0.0 -10 -18.5 -20 -87 -10 -16.899999999999999 -20 -87 -42 --0.41421356237308982 -10 -15.400000000000006 -20 -88.499999999999972 -10 -15.4 -20 -100 -10 -20 -20 -100 -10 -19.999999999999996 -20 -88.499999999999972 -42 --0.41421356237308982 -0 -LWPOLYLINE -5 -128 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -4 -70 -1 -43 -0.0 -10 -54.150000000000006 -20 -62.034999999999997 -42 --0.99999999999999989 -10 -52.950000000000003 -20 -62.034999999999997 -10 -52.95000000000001 -20 -63.335000000000001 -42 --0.99999999999999989 -10 -54.149999999999999 -20 -63.335000000000001 -0 -CIRCLE -5 -129 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -49.950000000000003 -20 -62.685000000000002 -30 -0 -40 -0.59999999999999998 -0 -ARC -5 -130 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -53.550000000000004 -20 -62.034999999999997 -30 -0 -40 -0.60000000000000497 -100 -AcDbArc -50 --180 -51 -0 -0 -LINE -5 -131 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -72.874812992585703 -20 -48.312219961316394 -30 -0 -11 -72.649070361618698 -21 -49.592470040232264 -31 -0 -0 -ARC -5 -132 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -53.550000000000004 -20 -63.335000000000001 -30 -0 -40 -0.59999999999999609 -100 -AcDbArc -50 -0 -51 -180 -0 -LINE -5 -133 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -85.353090375476171 -20 -51.832531532135668 -30 -0 -11 -85.578833006443176 -21 -50.552281453219805 -31 -0 -0 -CIRCLE -5 -134 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -45.450000000000003 -20 -62.685000000000002 -30 -0 -40 -0.59999999999999998 -0 -LINE -5 -135 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -73.830839665233341 -20 -49.800847853432586 -30 -0 -11 -74.056582296200347 -21 -48.520597774516723 -31 -0 -0 -LINE -5 -136 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -84.397063702828561 -20 -50.343903640019477 -30 -0 -11 -84.171321071861513 -21 -51.624153718935347 -31 -0 -0 -LINE -5 -137 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -52.950000000000003 -20 -62.034999999999997 -30 -0 -11 -52.950000000000003 -21 -63.335000000000001 -31 -0 -0 -LWPOLYLINE -5 -138 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -6 -70 -1 -43 -0.0 -10 -78.000000000000028 -20 -88.499999999999972 -10 -78.000000000000028 -20 -100 -10 -82.220000000000027 -20 -100 -10 -82.220000000000027 -20 -88.5 -42 --0.4142135623730881 -10 -80.720000000000027 -20 -87 -10 -79.500000000000028 -20 -87 -42 --0.41421356237308982 -0 -ARC -5 -139 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -84.76220572366887 -20 -51.728342625535511 -30 -0 -40 -0.59999999999996168 -100 -AcDbArc -50 -10.000000000000307 -51 -190.00000000000006 -0 -ARC -5 -140 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -73.239955013426027 -20 -49.696658946832429 -30 -0 -40 -0.59999999999999665 -100 -AcDbArc -50 -10.000000000000087 -51 -190.00000000000051 -0 -CIRCLE -5 -141 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -81.329769128308413 -20 -50.463084146476625 -30 -0 -40 -0.59999999999999987 -0 -CIRCLE -5 -142 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -76.898134239753475 -20 -49.681667346975445 -30 -0 -40 -0.59999999999999987 -0 -ARC -5 -143 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -84.987948354635876 -20 -50.448092546619641 -30 -0 -40 -0.5999999999999982 -100 -AcDbArc -50 --169.99999999999923 -51 -10.000000000000965 -0 -ARC -5 -144 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -73.465697644393032 -20 -48.416408867916559 -30 -0 -40 -0.5999999999999982 -100 -AcDbArc -50 --169.99999999999946 -51 -10.000000000000746 -0 -LINE -5 -145 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -54.149999999999999 -20 -63.335000000000001 -30 -0 -11 -54.149999999999999 -21 -62.034999999999997 -31 -0 -0 -ARC -5 -146 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -1.8999999999999884 -20 -58.500000000000014 -30 -0 -40 -1.5000000000000124 -100 -AcDbArc -50 -270.00000000000045 -51 -360 -0 -CIRCLE -5 -147 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -3.5000000000000004 -20 -39.300000000000004 -30 -0 -40 -1.375 -0 -CIRCLE -5 -148 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -3.5000000000000004 -20 -16.800000000000001 -30 -0 -40 -1.375 -0 -LWPOLYLINE -5 -149 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -4 -70 -1 -43 -0.0 -10 -32.95000000000001 -20 -63.335000000000001 -42 --0.99999999999999989 -10 -34.149999999999999 -20 -63.335000000000001 -10 -34.150000000000006 -20 -62.034999999999997 -42 --0.99999999999999989 -10 -32.950000000000003 -20 -62.034999999999997 -0 -LWPOLYLINE -5 -150 -100 -AcDbEntity -8 -0 -100 -AcDbPolyline -90 -4 -70 -1 -43 -0.0 -10 -41.250000000000007 -20 -63.335000000000001 -42 --0.99999999999999989 -10 -42.450000000000003 -20 -63.335000000000001 -10 -42.45000000000001 -20 -62.034999999999997 -42 --0.99999999999999989 -10 -41.25 -20 -62.034999999999997 -0 -ARC -5 -151 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -41.850000000000009 -20 -63.335000000000001 -30 -0 -40 -0.59999999999999609 -100 -AcDbArc -50 -0 -51 -180 -0 -ARC -5 -152 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -41.850000000000009 -20 -62.034999999999997 -30 -0 -40 -0.60000000000000497 -100 -AcDbArc -50 --180 -51 -0 -0 -ARC -5 -153 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -33.550000000000004 -20 -63.335000000000001 -30 -0 -40 -0.59999999999999609 -100 -AcDbArc -50 -0 -51 -180 -0 -ARC -5 -154 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -21.850000000000001 -20 -62.034999999999997 -30 -0 -40 -0.60000000000000053 -100 -AcDbArc -50 --180 -51 -0 -0 -CIRCLE -5 -155 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -25.449999999999999 -20 -62.685000000000002 -30 -0 -40 -0.59999999999999998 -0 -ARC -5 -156 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -33.550000000000004 -20 -62.034999999999997 -30 -0 -40 -0.60000000000000497 -100 -AcDbArc -50 --180 -51 -0 -0 -LINE -5 -157 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -22.450000000000003 -20 -63.335000000000001 -30 -0 -11 -22.450000000000003 -21 -62.034999999999997 -31 -0 -0 -LINE -5 -158 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -34.149999999999999 -20 -63.335000000000001 -30 -0 -11 -34.149999999999999 -21 -62.034999999999997 -31 -0 -0 -LINE -5 -159 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -32.950000000000003 -20 -62.034999999999997 -30 -0 -11 -32.950000000000003 -21 -63.335000000000001 -31 -0 -0 -LINE -5 -160 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -21.25 -20 -62.034999999999997 -30 -0 -11 -21.25 -21 -63.335000000000001 -31 -0 -0 -LINE -5 -161 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -42.450000000000003 -20 -63.335000000000001 -30 -0 -11 -42.450000000000003 -21 -62.034999999999997 -31 -0 -0 -LINE -5 -162 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -41.25 -20 -62.034999999999997 -30 -0 -11 -41.25 -21 -63.335000000000001 -31 -0 -0 -ARC -5 -163 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -66.500000000000014 -20 -3.5002504107472014 -30 -0 -40 -1.500000000000012 -100 -AcDbArc -50 -90.00000000000054 -51 -180 -0 -ARC -5 -164 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -62 -20 -3.0000000000000004 -30 -0 -40 -3.0000000000000004 -100 -AcDbArc -50 --90 -51 -0 -0 -CIRCLE -5 -165 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -61.5 -20 -39.300000000000004 -30 -0 -40 -1.375 -0 -LINE -5 -166 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -66.5 -20 -5.0002504107472134 -30 -0 -11 -66.5 -21 -5.0002504107472134 -31 -0 -0 -CIRCLE -5 -167 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -61.5 -20 -16.800000000000001 -30 -0 -40 -1.375 -0 -LINE -5 -168 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -68 -20 -3.5002504107472134 -30 -0 -11 -68 -21 -4.3709567898628133e-16 -31 -0 -0 -LINE -5 -169 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -65 -20 -3.5002504107472134 -30 -0 -11 -65 -21 -3.0000000000000004 -31 -0 -0 -LINE -5 -170 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -68 -20 -4.3709567898628133e-16 -30 -0 -11 -62 -21 -0 -31 -0 -0 -LINE -5 -171 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -3.0000000000000004 -20 -0 -30 -0 -11 -0 -21 -0 -31 -0 -0 -LINE -5 -172 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -0 -20 -0 -30 -0 -11 -0 -21 -3.0000000000000009 -31 -0 -0 -LINE -5 -173 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -0 -20 -60 -30 -0 -11 -0 -21 -57 -31 -0 -0 -ARC -5 -174 -100 -AcDbEntity -8 -0 -100 -AcDbCircle -10 -66.5 -20 -3.5002504107472014 -30 -0 -40 -1.5000000000000124 -100 -AcDbArc -50 -0 -51 -90 -0 -ENDSEC -0 -SECTION -2 -OBJECTS -0 -DICTIONARY -5 -C -100 -AcDbDictionary -3 -ACAD_GROUP -350 -D -3 -ACAD_MLINESTYLE -350 -17 -0 -DICTIONARY -5 -D -100 -AcDbDictionary -0 -DICTIONARY -5 -1A -330 -C -100 -AcDbDictionary -0 -DICTIONARY -5 -17 -100 -AcDbDictionary -0 -ENDSEC -0 -EOF diff --git a/examples/panelize.py b/examples/panelize.py index 34cc446..20a2cac 100755 --- a/examples/panelize.py +++ b/examples/panelize.py @@ -18,7 +18,6 @@ boards=[ ] outline = 'inputs/outline.dxf' mousebites = 'inputs/mousebites.dxf' -fill = 'inputs/fill.dxf' outputs = 'outputs/panelized' os.chdir(os.path.dirname(__file__)) @@ -62,9 +61,11 @@ file = gerberex.read(outline) file.write(outputs + '.GML') putstr('.') ctx = GerberComposition() -file = gerberex.read(fill) -file.to_metric() +base = gerberex.rectangle(width=100, height=100, left=0, bottom=0, units='metric') +base.draw_mode = DxfFile.DM_FILL +ctx.merge(base) file.draw_mode = DxfFile.DM_FILL +file.negate_polarity() ctx.merge(file) ctx.dump(outputs + '-fill.GML') diff --git a/gerberex/dxf.py b/gerberex/dxf.py index 00b7695..95a3114 100644 --- a/gerberex/dxf.py +++ b/gerberex/dxf.py @@ -12,12 +12,88 @@ from gerber.gerber_statements import ADParamStmt from gerber.excellon_statements import ExcellonTool from gerber.excellon_statements import CoordinateStmt from gerberex.utility import is_equal_point, is_equal_value -from gerberex.dxf_path import generate_paths +from gerberex.dxf_path import generate_paths, judge_containment from gerberex.excellon import write_excellon_header from gerberex.rs274x import write_gerber_header ACCEPTABLE_ERROR = 0.001 +def _normalize_angle(start_angle, end_angle): + angle = end_angle - start_angle + if angle > 0: + start = start_angle % 360 + else: + angle = -angle + start = end_angle % 360 + angle = min(angle, 360) + start = start - 360 if start > 180 else start + + regions = [] + while angle > 0: + end = start + angle + if end <= 180: + regions.append((start * pi / 180, end * pi / 180)) + angle = 0 + else: + regions.append((start * pi / 180, pi)) + angle = end - 180 + start = -180 + return regions + +def _intersections_of_line_and_circle(start, end, center, radius, error_range): + x1 = start[0] - center[0] + y1 = start[1] - center[1] + x2 = end[0] - center[0] + y2 = end[1] - center[1] + + dx = x2 - x1 + dy = y2 - y1 + dr = sqrt(dx * dx + dy * dy) + D = x1 * y2 - x2 * y1 + + D2 = D * D + dr2 = dr * dr + r2 = radius * radius + delta = r2 * dr2 - D2 + e4 = error_range * error_range * error_range * error_range * 10 + if delta > - e4 and delta < e4: + delta = 0 + if delta < 0: + return None + + sqrt_D = sqrt(delta) + E_x = -dx * sqrt_D if dy < 0 else dx * sqrt_D + E_y = abs(dy) * sqrt_D + + p1_x = (D * dy + E_x) / dr2 + p2_x = (D * dy - E_x) / dr2 + p1_y = (-D * dx + E_y) / dr2 + p2_y = (-D * dx - E_y) / dr2 + + p1_angle = atan2(p1_y, p1_x) + p2_angle = atan2(p2_y, p2_x) + if dx == 0: + p1_t = (p1_y - y1) / dy + p2_t = (p2_y - y1) / dy + else: + p1_t = (p1_x - x1) / dx + p2_t = (p2_x - x1) / dx + + if delta == 0: + return ( + (p1_x + center[0], p1_y + center[1]), + None, + p1_angle, None, + p1_t, None + ) + else: + return ( + (p1_x + center[0], p1_y + center[1]), + (p2_x + center[0], p2_y + center[1]), + p1_angle, p2_angle, + p1_t, p2_t + ) + class DxfStatement(object): def __init__(self, entity): self.entity = entity @@ -51,6 +127,13 @@ class DxfLineStatement(DxfStatement): end = (entity.end[0], entity.end[1]) return cls(entity, start, end) + @property + def bounding_box(self): + return (min(self.start[0], self.end[0]), + min(self.start[1], self.end[1]), + max(self.start[0], self.end[0]), + max(self.start[1], self.end[1])) + def __init__(self, entity, start, end): super(DxfLineStatement, self).__init__(entity) self.start = start @@ -110,6 +193,53 @@ class DxfLineStatement(DxfStatement): def rotate(self, angle, center=(0, 0)): self.start = rotate_point(self.start, angle, center) self.end = rotate_point(self.end, angle, center) + + def intersections_with_halfline(self, point_from, point_to, error_range): + denominator = (self.end[0] - self.start[0]) * (point_to[1] - point_from[1]) - \ + (self.end[1] - self.start[1]) * (point_to[0] - point_from[0]) + de = error_range * error_range + if denominator > -de and denominator < de: + return [] + from_dx = point_from[0] - self.start[0] + from_dy = point_from[1] - self.start[1] + r = ((point_to[1] - point_from[1]) * from_dx - + (point_to[0] - point_from[0]) * from_dy) / denominator + s = ((self.end[1] - self.start[1]) * from_dx - + (self.end[0] - self.start[0]) * from_dy) / denominator + dx = (self.end[0] - self.start[0]) + dy = (self.end[1] - self.start[1]) + le = error_range / sqrt(dx * dx + dy * dy) + if s < 0 or r < -le or r > 1 + le: + return [] + + pt = (self.start[0] + (self.end[0] - self.start[0]) * r, + self.start[1] + (self.end[1] - self.start[1]) * r) + if is_equal_point(pt, self.start, error_range): + return [] + else: + return [pt] + + def intersections_with_arc(self, center, radius, angle_regions, error_range): + intersection = \ + _intersections_of_line_and_circle(self.start, self.end, center, radius, error_range) + if intersection is None: + return [] + else: + p1, p2, p1_angle, p2_angle, p1_t, p2_t = intersection + + pts = [] + if p1_t >= 0 and p1_t <= 1: + for region in angle_regions: + if p1_angle >= region[0] and p1_angle <= region[1]: + pts.append(p1) + break + if p2 is not None and p2_t >= 0 and p2_t <= 1: + for region in angle_regions: + if p2_angle >= region[0] and p2_angle <= region[1]: + pts.append(p2) + break + + return pts class DxfArcStatement(DxfStatement): def __init__(self, entity): @@ -139,6 +269,12 @@ class DxfArcStatement(DxfStatement): self.is_closed = angle >= 360 or angle <= -360 else: raise Exception('invalid DXF type was specified') + self.angle_regions = _normalize_angle(self.start_angle, self.end_angle) + + @property + def bounding_box(self): + return (self.center[0] - self.radius, self.center[1] - self.radius, + self.center[0] + self.radius, self.center[1] + self.radius) def to_inch(self): self.radius = inch(self.radius) @@ -204,6 +340,82 @@ class DxfArcStatement(DxfStatement): self.center = rotate_point(self.center, angle, center) self.start = rotate_point(self.start, angle, center) self.end = rotate_point(self.end, angle, center) + self.angle_regions = _normalize_angle(self.start_angle, self.end_angle) + + def intersections_with_halfline(self, point_from, point_to, error_range): + intersection = \ + _intersections_of_line_and_circle( + point_from, point_to, self.center, self.radius, error_range) + if intersection is None: + return [] + else: + p1, p2, p1_angle, p2_angle, p1_t, p2_t = intersection + + if is_equal_point(p1, self.start, error_range): + p1 = None + elif p2 is not None and is_equal_point(p2, self.start, error_range): + p2 = None + + aerror = error_range * self.radius + pts = [] + if p1 is not None and p1_t >= 0 and not is_equal_point(p1, self.start, error_range): + for region in self.angle_regions: + if p1_angle >= region[0] - aerror and p1_angle <= region[1] + aerror: + pts.append(p1) + break + if p2 is not None and p2_t >= 0 and not is_equal_point(p2, self.start, error_range): + for region in self.angle_regions: + if p2_angle >= region[0] - aerror and p2_angle <= region[1] + aerror: + pts.append(p2) + break + + return pts + + def intersections_with_arc(self, center, radius, angle_regions, error_range): + x1 = center[0] - self.center[0] + y1 = center[1] - self.center[1] + r1 = self.radius + r2 = radius + cd_sq = x1 * x1 + y1 * y1 + cd = sqrt(cd_sq) + rd = abs(r1 - r2) + + if (cd >= 0 and cd <= rd) or cd >= r1 + r2: + return [] + + A = (cd_sq + r1 * r1 - r2 * r2) / 2 + scale = sqrt(cd_sq * r1 * r1 - A * A) / cd_sq + xl = A * x1 / cd_sq + xr = y1 * scale + yl = A * y1 / cd_sq + yr = x1 * scale + + pt1_x = xl + xr + pt1_y = yl - yr + pt2_x = xl - xr + pt2_y = yl + yr + pt1_angle1 = atan2(pt1_y, pt1_x) + pt1_angle2 = atan2(pt1_y - y1, pt1_x - x1) + pt2_angle1 = atan2(pt2_y, pt2_x) + pt2_angle2 = atan2(pt2_y - y1, pt2_x - x1) + + aerror = error_range * self.radius + pts=[] + for region in self.angle_regions: + if pt1_angle1 >= region[0] and pt1_angle1 <= region[1]: + for region in angle_regions: + if pt1_angle2 >= region[0] - aerror and pt1_angle2 <= region[1] + aerror: + pts.append((pt1_x + self.center[0], pt1_y + self.center[1])) + break + break + for region in self.angle_regions: + if pt2_angle1 >= region[0] and pt2_angle1 <= region[1]: + for region in angle_regions: + if pt2_angle2 >= region[0] - aerror and pt2_angle2 <= region[1] + aerror: + pts.append((pt2_x + self.center[0], pt2_y + self.center[1])) + break + break + return pts class DxfPolylineStatement(DxfStatement): def __init__(self, entity): @@ -293,31 +505,69 @@ class DxfPolylineStatement(DxfStatement): self.entity.points[idx] = rotate_point(self.entity.points[idx], angle, center) class DxfStatements(object): - def __init__(self, statements, units, dcode=10, draw_mode=None): - if draw_mode == None: + def __init__(self, statements, units, dcode=10, draw_mode=None, fill_mode=None): + if draw_mode is None: draw_mode = DxfFile.DM_LINE + if fill_mode is None: + fill_mode = DxfFile.FM_TURN_OVER self._units = units self.dcode = dcode self.draw_mode = draw_mode + self.fill_mode = fill_mode self.pitch = inch(1) if self._units == 'inch' else 1 self.width = 0 self.error_range = inch(ACCEPTABLE_ERROR) if self._units == 'inch' else ACCEPTABLE_ERROR - self.statements = statements + self.statements = list(filter( + lambda i: not (isinstance(i, DxfLineStatement) and \ + is_equal_point(i.start, i.end, self.error_range)), + statements + )) self.close_paths, self.open_paths = generate_paths(self.statements, self.error_range) + self.sorted_close_paths = [] + self.polarity = True # True means dark, False means clear @property def units(self): return _units + def _polarity_command(self, polarity=None): + if polarity is None: + polarity = self.polarity + return '%LPD*%' if polarity else '%LPC*%' + + def _prepare_sorted_close_paths(self): + if self.sorted_close_paths: + return + for i in range(0, len(self.close_paths)): + for j in range(i + 1, len(self.close_paths)): + containee, container = judge_containment( + self.close_paths[i], self.close_paths[j], self.error_range) + if containee is not None: + containee.containers.append(container) + self.sorted_close_paths = sorted(self.close_paths, key=lambda path: len(path.containers)) + def to_gerber(self, settings=FileSettings()): def gerbers(): yield 'G75*' - yield '%LPD*%' + yield self._polarity_command() yield 'D{0}*'.format(self.dcode) if self.draw_mode == DxfFile.DM_FILL: yield 'G36*' - for path in self.close_paths: - yield path.to_gerber(settings) + if self.fill_mode == DxfFile.FM_TURN_OVER: + self._prepare_sorted_close_paths() + polarity = self.polarity + level = 0 + for path in self.sorted_close_paths: + if len(path.containers) > level: + level = len(path.containers) + polarity = not polarity + yield 'G37*' + yield self._polarity_command(polarity) + yield 'G36*' + yield path.to_gerber(settings) + else: + for path in self.close_paths: + yield path.to_gerber(settings) yield 'G37*' else: pitch = self.pitch if self.draw_mode == DxfFile.DM_MOUSE_BITES else 0 @@ -378,6 +628,9 @@ class DxfFile(CamFile): DM_FILL = 1 DM_MOUSE_BITES = 2 + FM_SIMPLE = 0 + FM_TURN_OVER = 1 + FT_RX274X = 0 FT_EXCELLON = 1 @@ -430,6 +683,7 @@ class DxfFile(CamFile): super(DxfFile, self).__init__(settings=settings, filename=filename) self._draw_mode = draw_mode + self._fill_mode = self.FM_TURN_OVER self.aperture = ADParamStmt.circle(dcode=10, diameter=0.0) if settings.units == 'inch': @@ -437,7 +691,7 @@ class DxfFile(CamFile): else: self.aperture.to_metric() self.statements = DxfStatements( - statements, self.units, dcode=self.aperture.d, draw_mode=self.draw_mode) + statements, self.units, dcode=self.aperture.d, draw_mode=self.draw_mode, fill_mode=self.filename) @property def dcode(self): @@ -466,6 +720,15 @@ class DxfFile(CamFile): self._draw_mode = value self.statements.draw_mode = value + @property + def fill_mode(self): + return self._fill_mode + + @fill_mode.setter + def fill_mode(self, value): + self._fill_mode = value + self.statements.fill_mode = value + @property def pitch(self): return self.statements.pitch @@ -512,6 +775,9 @@ class DxfFile(CamFile): def rotate(self, angle, center=(0, 0)): self.statements.rotate(angle, center) + def negate_polarity(self): + self.statements.polarity = not self.statements.polarity + def loads(data, filename=None): if sys.version_info.major == 2: data = unicode(data) diff --git a/gerberex/dxf_path.py b/gerberex/dxf_path.py index 1307411..bb620ff 100644 --- a/gerberex/dxf_path.py +++ b/gerberex/dxf_path.py @@ -5,13 +5,17 @@ from gerber.utils import inch, metric, write_gerber_value from gerber.cam import FileSettings -from gerberex.utility import is_equal_point, is_equal_value +from gerberex.utility import is_equal_point, is_equal_value, normalize_vec2d, dot_vec2d from gerberex.excellon import CoordinateStmtEx class DxfPath(object): def __init__(self, statements, error_range=0): self.statements = statements self.error_range = error_range + self.bounding_box = statements[0].bounding_box + self.containers = [] + for statement in statements[1:]: + self._merge_bounding_box(statement.bounding_box) @property def start(self): @@ -116,12 +120,15 @@ class DxfPath(object): if j > 0: del mergee[-j] del self.statements[0:j] + for statement in mergee: + self._merge_bounding_box(statement.bounding_box) self.statements.extend(mergee) return True else: if self.statements[-1].is_equal_to(element, error_range) or \ self.statements[0].is_equal_to(element, error_range): return False + self._merge_bounding_box(element.bounding_box) self.statements.appen(element) return True @@ -153,6 +160,21 @@ class DxfPath(object): self.statements.insert(0, element) return True + def _merge_bounding_box(self, box): + self.bounding_box = (min(self.bounding_box[0], box[0]), + min(self.bounding_box[1], box[1]), + max(self.bounding_box[2], box[2]), + max(self.bounding_box[3], box[3])) + + def may_be_in_collision(self, path): + if self.bounding_box[0] >= path.bounding_box[2] or \ + self.bounding_box[1] >= path.bounding_box[3] or \ + self.bounding_box[2] <= path.bounding_box[0] or \ + self.bounding_box[3] <= path.bounding_box[1]: + return False + else: + return True + def to_gerber(self, settings=FileSettings(), pitch=0, width=0): from gerberex.dxf import DxfArcStatement if pitch == 0: @@ -244,7 +266,61 @@ class DxfPath(object): out += ploter(dot[0], dot[1]) return out + def intersections_with_halfline(self, point_from, point_to, error_range=0): + def calculator(statement): + return statement.intersections_with_halfline(point_from, point_to, error_range) + def validator(pt, statement, idx): + if is_equal_point(pt, statement.end, error_range) and \ + not self._judge_cross(point_from, point_to, idx, error_range): + return False + return True + return self._collect_intersections(calculator, validator, error_range) + + def intersections_with_arc(self, center, radius, angle_regions, error_range=0): + def calculator(statement): + return statement.intersections_with_arc(center, radius, angle_regions, error_range) + return self._collect_intersections(calculator, None, error_range) + def _collect_intersections(self, calculator, validator, error_range): + allpts = [] + last = allpts + for i in range(0, len(self.statements)): + statement = self.statements[i] + cur = calculator(statement) + if cur: + for pt in cur: + for dest in allpts: + if is_equal_point(pt, dest, error_range): + break + else: + if validator is not None and not validator(pt, statement, i): + continue + allpts.append(pt) + last = cur + return allpts + + def _judge_cross(self, from_pt, to_pt, index, error_range): + standard = normalize_vec2d((to_pt[0] - from_pt[0], to_pt[1] - from_pt[1])) + normal = (standard[1], standard[0]) + def statements(): + for i in range(index, len(self.statements)): + yield self.statements[i] + for i in range(0, index): + yield self.statements[i] + dot_standard = None + for statement in statements(): + tstart = statement.start + tend = statement.end + target = normalize_vec2d((tend[0] - tstart[0], tend[1] - tstart[1])) + dot= dot_vec2d(normal, target) + if dot_standard is None: + dot_standard = dot + continue + if is_equal_point(standard, target, error_range): + continue + return (dot_standard > 0 and dot > 0) or (dot_standard < 0 and dot < 0) + raise Exception('inconsistensy is detected while cross judgement between paths') + def generate_paths(statements, error_range=0): from gerberex.dxf import DxfPolylineStatement @@ -287,3 +363,50 @@ def generate_paths(statements, error_range=0): closed_path = list(filter(lambda p: p.is_closed, paths)) open_path = list(filter(lambda p: not p.is_closed, paths)) return (closed_path, open_path) + +def judge_containment(path1, path2, error_range=0): + from gerberex.dxf import DxfArcStatement, DxfLineStatement + + nocontainment = (None, None) + if not path1.may_be_in_collision(path2): + return nocontainment + + def is_in_line_segment(point_from, point_to, point): + dx = point_to[0] - point_from[0] + ratio = (point[0] - point_from[0]) / dx if dx != 0 else \ + (point[1] - point_from[1]) / (point_to[1] - point_from[1]) + return ratio >= 0 and ratio <= 1 + + def contain_in_path(statement, path): + if isinstance(statement, DxfLineStatement): + segment = (statement.start, statement.end) + elif isinstance(statement, DxfArcStatement): + if statement.start == statement.end: + segment = (statement.start, statement.center) + else: + segment = (statement.start, statement.end) + else: + raise Exception('invalid dxf statement type') + pts = path.intersections_with_halfline(segment[0], segment[1], error_range) + if len(pts) % 2 == 0: + return False + for pt in pts: + if is_in_line_segment(segment[0], segment[1], pt): + return False + if isinstance(statement, DxfArcStatement): + pts = path.intersections_with_arc( + statement.center, statement.radius, statement.angle_regions, error_range) + if len(pts) > 0: + return False + return True + + if contain_in_path(path1.statements[0], path2): + containment = [path1, path2] + elif contain_in_path(path2.statements[0], path1): + containment = [path2, path1] + else: + return nocontainment + for i in range(1, len(containment[0].statements)): + if not contain_in_path(containment[0].statements[i], containment[1]): + return nocontainment + return containment diff --git a/gerberex/utility.py b/gerberex/utility.py index 4c89fa6..37de5e8 100644 --- a/gerberex/utility.py +++ b/gerberex/utility.py @@ -3,7 +3,7 @@ # Copyright 2019 Hiroshi Murayama -from math import cos, sin, pi +from math import cos, sin, pi, sqrt def rotate(x, y, angle, center): x0 = x - center[0] @@ -18,3 +18,10 @@ def is_equal_value(a, b, error_range=0): def is_equal_point(a, b, error_range=0): return is_equal_value(a[0], b[0], error_range) and \ is_equal_value(a[1], b[1], error_range) + +def normalize_vec2d(vec): + length = sqrt(vec[0] * vec[0] + vec[1] * vec[1]) + return (vec[0] / length, vec[1] / length) + +def dot_vec2d(vec1, vec2): + return vec1[0] * vec2[0] + vec1[1] * vec2[1] \ No newline at end of file diff --git a/setup.py b/setup.py index 6f144cb..bfe25c1 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ def read(fname): METADATA = { 'name': 'pcb-tools-extension', - 'version': "0.9.1", + 'version': "0.9.2", 'author': 'Hiroshi Murayama ', 'author_email': "opiopan@gmail.com", 'description': ("Extension for pcb-tools package to panelize gerber files"), diff --git a/tests/data/ref_dxf_metric.dxf b/tests/data/ref_dxf_metric.dxf index 89af1e7..8861d4b 100644 --- a/tests/data/ref_dxf_metric.dxf +++ b/tests/data/ref_dxf_metric.dxf @@ -271,49 +271,105 @@ AcDbPolyline 43 0.0 10 -9 +40 20 0 10 -1 +9.9999999999999982 20 -0 +1.1102230246251565e-15 42 --0.41421356237309515 +-0.41421356237309565 10 -0 +1.1102230246251565e-15 +20 +10 +10 +1.1102230246251565e-15 20 -0.99999999999999978 +40 +42 +-0.41421356237309553 +10 10 -6.9388939039072284e-16 20 -9 +50 +10 +40 +20 +50 +42 +-0.41421356237309603 +10 +50 +20 +40 +10 +50 +20 +9.9999999999999982 42 -0.41421356237309548 +0 +LWPOLYLINE +5 +101 +100 +AcDbEntity +8 +0 +100 +AcDbPolyline +90 +8 +70 +1 +43 +0.0 10 -0.99999999999999978 +74.270404858697972 20 +75.039392445007664 10 +74.270404858697972 +20 +45.039392445007664 +42 +-0.41421356237309553 10 -9 +64.270404858697972 20 +35.039392445007664 10 +34.270404858697965 +20 +35.039392445007664 42 --0.41421356237309509 +-0.41421356237309553 10 +24.270404858697965 +20 +45.039392445007664 10 +24.270404858697958 20 -9 +75.039392445007664 +42 +-0.41421356237309553 10 +34.270404858697965 +20 +85.039392445007678 10 +64.270404858697972 20 -1 +85.039392445007678 42 --0.41421356237309548 +-0.41421356237309603 0 CIRCLE 5 -101 +102 100 AcDbEntity 8 @@ -321,17 +377,121 @@ AcDbEntity 100 AcDbCircle 10 -0.61705708382705282 +80.154604804025013 20 +12.631646043929035 +30 +0 +40 +12.546259950593821 +210 +0 +220 +0 +230 +1 +0 +CIRCLE 5 +103 +100 +AcDbEntity +8 +0 +100 +AcDbCircle +10 +50 +20 +65 30 0 40 -0.29999999999999999 +10.277260744660863 +210 +0 +220 +0 +230 +1 +0 +ARC +5 +104 +100 +AcDbEntity +8 +0 +100 +AcDbCircle +10 +50 +20 +65 +30 +0 +40 +6.4592498736207826 +210 +0 +220 +-0 +230 +1 +100 +AcDbArc +50 +90 +51 +345.73898023603914 +0 +LINE +5 +105 +100 +AcDbEntity +8 +0 +100 +AcDbLine +10 +50 +20 +65 +30 +0 +11 +56.26019871530297 +21 +63.408830312383643 +31 +0 +0 +LINE +5 +106 +100 +AcDbEntity +8 +0 +100 +AcDbLine +10 +50 +20 +65 +30 +0 +11 +50 +21 +71.459249873620777 +31 +0 0 LWPOLYLINE 5 -102 +107 100 AcDbEntity 8 @@ -339,25 +499,115 @@ AcDbEntity 100 AcDbPolyline 90 -3 +4 70 1 43 0.0 10 -0.91705708382705309 +38.203772564818578 20 -7.5106817728417301 -42 --0.67748879940688445 +42.206179116779516 +10 +13.451174232106741 +20 +42.206179116779516 +10 +13.451174232106741 +20 +13.596032991956758 +10 +38.203772564818578 +20 +13.596032991956758 +0 +LINE +5 +108 +100 +AcDbEntity +8 +0 +100 +AcDbLine +10 +80 +20 +85 +30 +0 +11 +80 +21 +35 +31 +0 +0 +LINE +5 +109 +100 +AcDbEntity +8 +0 +100 +AcDbLine 10 -0.39955725374872897 +90 20 -7.3040569342673214 +85 +30 +0 +11 +90 +21 +35 +31 +0 +0 +LINE +5 +110 +100 +AcDbEntity +8 +0 +100 +AcDbLine 10 -0.61705708382705282 20 -7.5106817728417301 +20 +32.938987371135568 +30 +0 +11 +32.582672402541192 +21 +32.938987371135568 +31 +0 +0 +LINE +5 +111 +100 +AcDbEntity +8 +0 +100 +AcDbLine +10 +32.582672402541192 +20 +32.938987371135568 +30 +0 +11 +32.582672402541192 +21 +17.844276543429842 +31 +0 0 ENDSEC 0 diff --git a/tests/data/ref_dxf_mousebites.dxf b/tests/data/ref_dxf_mousebites.dxf deleted file mode 100644 index fcc56a5..0000000 --- a/tests/data/ref_dxf_mousebites.dxf +++ /dev/null @@ -1,344 +0,0 @@ -0 -SECTION -2 -HEADER -9 -$INSUNITS -70 -4 -9 -$ACADVER -1 -AC1014 -9 -$HANDSEED -5 -FFFF -0 -ENDSEC -0 -SECTION -2 -TABLES -0 -TABLE -2 -VPORT -5 -8 -100 -AcDbSymbolTable -0 -ENDTAB -0 -TABLE -2 -LTYPE -5 -5 -100 -AcDbSymbolTable -0 -LTYPE -5 -14 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord -2 -BYBLOCK -70 -0 -0 -LTYPE -5 -15 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord -2 -BYLAYER -70 -0 -0 -ENDTAB -0 -TABLE -2 -LAYER -5 -2 -100 -AcDbSymbolTable -70 -2 -0 -LAYER -5 -50 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord -2 -0 -70 -0 -6 -CONTINUOUS -0 -ENDTAB -0 -TABLE -2 -STYLE -5 -3 -100 -AcDbSymbolTable -70 -1 -0 -STYLE -5 -11 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord -2 -STANDARD -70 -0 -0 -ENDTAB -0 -TABLE -2 -VIEW -5 -6 -100 -AcDbSymbolTable -70 -0 -0 -ENDTAB -0 -TABLE -2 -UCS -5 -7 -100 -AcDbSymbolTable -70 -0 -0 -ENDTAB -0 -TABLE -2 -APPID -5 -9 -100 -AcDbSymbolTable -70 -2 -0 -APPID -5 -12 -100 -AcDbSymbolTableRecord -100 -AcDbRegAppTableRecord -2 -ACAD -70 -0 -0 -ENDTAB -0 -TABLE -2 -DIMSTYLE -5 -A -100 -AcDbSymbolTable -70 -1 -0 -ENDTAB -0 -TABLE -2 -BLOCK_RECORD -5 -1 -100 -AcDbSymbolTable -70 -1 -0 -BLOCK_RECORD -5 -1F -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord -2 -*MODEL_SPACE -0 -BLOCK_RECORD -5 -1B -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord -2 -*PAPER_SPACE -0 -ENDTAB -0 -ENDSEC -0 -SECTION -2 -BLOCKS -0 -BLOCK -5 -20 -100 -AcDbEntity -100 -AcDbBlockBegin -2 -*MODEL_SPACE -0 -ENDBLK -5 -21 -100 -AcDbEntity -100 -AcDbBlockEnd -0 -BLOCK -5 -1C -100 -AcDbEntity -100 -AcDbBlockBegin -2 -*PAPER_SPACE -0 -ENDBLK -5 -1D -100 -AcDbEntity -100 -AcDbBlockEnd -0 -ENDSEC -0 -SECTION -2 -ENTITIES -0 -LINE -5 -100 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -0.99999999999999933 -20 -9.0000000000000018 -30 -0 -11 -0.99999999999999967 -21 -0.99999999999999967 -31 -0 -0 -LINE -5 -101 -100 -AcDbEntity -8 -0 -100 -AcDbLine -10 -5 -20 -9.0000000000000018 -30 -0 -11 -5 -21 -0.99999999999999967 -31 -0 -0 -ENDSEC -0 -SECTION -2 -OBJECTS -0 -DICTIONARY -5 -C -100 -AcDbDictionary -3 -ACAD_GROUP -350 -D -3 -ACAD_MLINESTYLE -350 -17 -0 -DICTIONARY -5 -D -100 -AcDbDictionary -0 -DICTIONARY -5 -1A -330 -C -100 -AcDbDictionary -0 -DICTIONARY -5 -17 -100 -AcDbDictionary -0 -ENDSEC -0 -EOF diff --git a/tests/expects/dxf_offset.gtl b/tests/expects/dxf_offset.gtl index ff0cdda..df1b015 100644 --- a/tests/expects/dxf_offset.gtl +++ b/tests/expects/dxf_offset.gtl @@ -6,36 +6,88 @@ G75* %LPD*% D10* G01* -X200000Y50000D02* +X910000Y900000D02* G75* G01* -X120000Y50000D01* +X910000Y400000D01* +G01* +X1010000Y900000D02* +G75* +G01* +X1010000Y400000D01* +G01* +X310000Y379390D02* +G75* +G01* +X435827Y379390D01* +G01* +X435827Y228443D01* +G01* +X510000Y50000D02* +G75* +G01* +X210000Y50000D01* G02* -X110000Y60000I0J10000D01* +X110000Y150000I0J100000D01* G01* -X110000Y140000D01* +X110000Y450000D01* G02* -X120000Y150000I10000J0D01* +X210000Y550000I100000J0D01* G01* -X200000Y150000D01* +X510000Y550000D01* G02* -X210000Y140000I0J-10000D01* +X610000Y450000I0J-100000D01* G01* -X210000Y60000D01* +X610000Y150000D01* G02* -X200000Y50000I-10000J0D01* +X510000Y50000I-100000J0D01* G01* -X119171Y125107D02* +X852704Y800394D02* G75* +G01* +X852704Y500394D01* G02* -X113996Y123041I-3000J0D01* +X752704Y400394I-100000J0D01* G01* -X116171Y125107D01* +X452704Y400394D01* +G02* +X352704Y500394I0J100000D01* G01* -X119171Y125107D01* +X352704Y800394D01* +G02* +X452704Y900394I100000J0D01* +G01* +X752704Y900394D01* +G02* +X852704Y800394I0J-100000D01* G01* -X119171Y100000D02* +X492038Y472062D02* +G75* +G01* +X244512Y472062D01* +G01* +X244512Y185960D01* +G01* +X492038Y185960D01* +G01* +X492038Y472062D01* +G01* +X1037009Y176316D02* +G75* +G03* +X1037009Y176316I-125463J0D01* +G01* +X712773Y700000D02* G75* G03* -X119171Y100000I-3000J0D01* +X712773Y700000I-102773J0D01* +G01* +X610000Y700000D02* +G75* +G01* +X610000Y764592D01* +G03* +X672602Y684088I0J-64592D01* +G01* +X610000Y700000D01* M02* diff --git a/tests/expects/dxf_rotate.gtl b/tests/expects/dxf_rotate.gtl index c6449ca..5c04b64 100644 --- a/tests/expects/dxf_rotate.gtl +++ b/tests/expects/dxf_rotate.gtl @@ -6,36 +6,88 @@ G75* %LPD*% D10* G01* -X124805Y2611D02* +X501270Y1044184D02* G75* G01* -X49630Y-24751D01* +X672280Y574337D01* +G01* +X595239Y1078386D02* +G75* +G01* +X766249Y608539D01* +G01* +X115513Y349758D02* +G75* +G01* +X233752Y392793D01* +G01* +X285379Y250949D01* +G01* +X416110Y108637D02* +G75* +G01* +X134202Y6031D01* G02* -X36813Y-18774I-3420J9397D01* +X6031Y65798I-34202J93969D01* G01* -X9451Y56401D01* +X-96575Y347706D01* G02* -X15428Y69218I9397J3420D01* +X-36808Y475877I93969J34202D01* G01* -X90603Y96580D01* +X245100Y578483D01* G02* -X103420Y90603I3420J-9397D01* +X373271Y518716I34202J-93969D01* G01* -X130782Y15428D01* +X475877Y236808D01* G02* -X124805Y2611I-9397J-3420D01* +X416110Y108637I-93969J-34202D01* G01* -X23162Y45543D02* +X481496Y930988D02* G75* +G01* +X584102Y649080D01* G02* -X19006Y41831I-2819J-1026D01* +X524335Y520909I-93969J-34202D01* G01* -X20343Y44517D01* +X242427Y418303D01* +G02* +X114256Y478070I-34202J93969D01* G01* -X23162Y45543D01* +X11650Y759978D01* +G02* +X71417Y888149I93969J34202D01* +G01* +X353325Y990755D01* +G02* +X481496Y930988I34202J-93969D01* G01* -X31749Y21950D02* +X254877Y499102D02* +G75* +G01* +X22279Y414443D01* +G01* +X120131Y145595D01* +G01* +X352730Y230254D01* +G01* +X254877Y499102D01* +G01* +X868133Y407583D02* +G75* +G03* +X868133Y407583I-117896J-42911D01* +G01* +X384341Y788789D02* G75* G03* -X31749Y21950I-2819J-1026D01* +X384341Y788789I-96575J-35150D01* +G01* +X287766Y753639D02* +G75* +G01* +X265674Y814336D01* +G03* +X352035Y760098I22092J-60697D01* +G01* +X287766Y753639D01* M02* diff --git a/tests/expects/dxf_save_fill.gtl b/tests/expects/dxf_save_fill.gtl index f18c9f7..4b82fb2 100644 --- a/tests/expects/dxf_save_fill.gtl +++ b/tests/expects/dxf_save_fill.gtl @@ -7,37 +7,78 @@ G75* D10* G36* G01* -X90000Y0D02* +X400000Y0D02* G75* G01* -X10000Y0D01* +X100000Y0D01* G02* -X0Y10000I0J10000D01* +X0Y100000I0J100000D01* G01* -X0Y90000D01* +X0Y400000D01* G02* -X10000Y100000I10000J0D01* +X100000Y500000I100000J0D01* G01* -X90000Y100000D01* +X400000Y500000D01* G02* -X100000Y90000I0J-10000D01* +X500000Y400000I0J-100000D01* G01* -X100000Y10000D01* +X500000Y100000D01* G02* -X90000Y0I-10000J0D01* +X400000Y0I-100000J0D01* G01* -X9171Y75107D02* +X742704Y750394D02* G75* +G01* +X742704Y450394D01* +G02* +X642704Y350394I-100000J0D01* +G01* +X342704Y350394D01* +G02* +X242704Y450394I0J100000D01* +G01* +X242704Y750394D01* +G02* +X342704Y850394I100000J0D01* +G01* +X642704Y850394D01* G02* -X3996Y73041I-3000J0D01* +X742704Y750394I0J-100000D01* +G01* +X927009Y126316D02* +G75* +G03* +X927009Y126316I-125463J0D01* +G37* +%LPC*% +G36* G01* -X6171Y75107D01* +X382038Y422062D02* +G75* +G01* +X134512Y422062D01* +G01* +X134512Y135960D01* G01* -X9171Y75107D01* +X382038Y135960D01* +G01* +X382038Y422062D01* +G01* +X602773Y650000D02* +G75* +G03* +X602773Y650000I-102773J0D01* +G37* +%LPD*% +G36* G01* -X9171Y50000D02* +X500000Y650000D02* G75* +G01* +X500000Y714592D01* G03* -X9171Y50000I-3000J0D01* +X562602Y634088I0J-64592D01* +G01* +X500000Y650000D01* G37* M02* diff --git a/tests/expects/dxf_save_fill_simple.gtl b/tests/expects/dxf_save_fill_simple.gtl new file mode 100644 index 0000000..5ff4d55 --- /dev/null +++ b/tests/expects/dxf_save_fill_simple.gtl @@ -0,0 +1,78 @@ +%MOMM*% +%FSLAX34Y34*% +%IPPOS*% +%ADD10C,0*% +G75* +%LPD*% +D10* +G36* +G01* +X400000Y0D02* +G75* +G01* +X100000Y0D01* +G02* +X0Y100000I0J100000D01* +G01* +X0Y400000D01* +G02* +X100000Y500000I100000J0D01* +G01* +X400000Y500000D01* +G02* +X500000Y400000I0J-100000D01* +G01* +X500000Y100000D01* +G02* +X400000Y0I-100000J0D01* +G01* +X742704Y750394D02* +G75* +G01* +X742704Y450394D01* +G02* +X642704Y350394I-100000J0D01* +G01* +X342704Y350394D01* +G02* +X242704Y450394I0J100000D01* +G01* +X242704Y750394D01* +G02* +X342704Y850394I100000J0D01* +G01* +X642704Y850394D01* +G02* +X742704Y750394I0J-100000D01* +G01* +X382038Y422062D02* +G75* +G01* +X134512Y422062D01* +G01* +X134512Y135960D01* +G01* +X382038Y135960D01* +G01* +X382038Y422062D01* +G01* +X927009Y126316D02* +G75* +G03* +X927009Y126316I-125463J0D01* +G01* +X602773Y650000D02* +G75* +G03* +X602773Y650000I-102773J0D01* +G01* +X500000Y650000D02* +G75* +G01* +X500000Y714592D01* +G03* +X562602Y634088I0J-64592D01* +G01* +X500000Y650000D01* +G37* +M02* diff --git a/tests/expects/dxf_save_line.gtl b/tests/expects/dxf_save_line.gtl index d1966ad..b3ee8f1 100644 --- a/tests/expects/dxf_save_line.gtl +++ b/tests/expects/dxf_save_line.gtl @@ -1,41 +1,93 @@ %MOMM*% %FSLAX34Y34*% %IPPOS*% -%ADD10C,0*% +%ADD10C,0.2*% G75* %LPD*% D10* G01* -X90000Y0D02* +X800000Y850000D02* G75* G01* -X10000Y0D01* +X800000Y350000D01* +G01* +X900000Y850000D02* +G75* +G01* +X900000Y350000D01* +G01* +X200000Y329390D02* +G75* +G01* +X325827Y329390D01* +G01* +X325827Y178443D01* +G01* +X400000Y0D02* +G75* +G01* +X100000Y0D01* G02* -X0Y10000I0J10000D01* +X0Y100000I0J100000D01* G01* -X0Y90000D01* +X0Y400000D01* G02* -X10000Y100000I10000J0D01* +X100000Y500000I100000J0D01* G01* -X90000Y100000D01* +X400000Y500000D01* G02* -X100000Y90000I0J-10000D01* +X500000Y400000I0J-100000D01* G01* -X100000Y10000D01* +X500000Y100000D01* G02* -X90000Y0I-10000J0D01* +X400000Y0I-100000J0D01* G01* -X9171Y75107D02* +X742704Y750394D02* G75* +G01* +X742704Y450394D01* G02* -X3996Y73041I-3000J0D01* +X642704Y350394I-100000J0D01* G01* -X6171Y75107D01* +X342704Y350394D01* +G02* +X242704Y450394I0J100000D01* G01* -X9171Y75107D01* +X242704Y750394D01* +G02* +X342704Y850394I100000J0D01* +G01* +X642704Y850394D01* +G02* +X742704Y750394I0J-100000D01* G01* -X9171Y50000D02* +X382038Y422062D02* +G75* +G01* +X134512Y422062D01* +G01* +X134512Y135960D01* +G01* +X382038Y135960D01* +G01* +X382038Y422062D01* +G01* +X927009Y126316D02* +G75* +G03* +X927009Y126316I-125463J0D01* +G01* +X602773Y650000D02* G75* G03* -X9171Y50000I-3000J0D01* +X602773Y650000I-102773J0D01* +G01* +X500000Y650000D02* +G75* +G01* +X500000Y714592D01* +G03* +X562602Y634088I0J-64592D01* +G01* +X500000Y650000D01* M02* diff --git a/tests/expects/dxf_save_line.txt b/tests/expects/dxf_save_line.txt new file mode 100644 index 0000000..c3d73d4 --- /dev/null +++ b/tests/expects/dxf_save_line.txt @@ -0,0 +1,84 @@ +M48 +FMAT,2 +ICI,OFF +METRIC,TZ,000.000 +T01C0.200 +% +G90 +M71 +T01 +G00X80000Y85000 +M15 +G01X80000Y35000 +M16 +G05 + +G00X90000Y85000 +M15 +G01X90000Y35000 +M16 +G05 + +G00X20000Y32939 +M15 +G01X32583Y32939 +G01X32583Y17844 +M16 +G05 + +G00X40000Y0 +M15 +G01X10000Y0 +G02X0Y10000I0J10000 +G01X0Y40000 +G02X10000Y50000I10000J0 +G01X40000Y50000 +G02X50000Y40000I0J-10000 +G01X50000Y10000 +G02X40000Y0I-10000J0 +M16 +G05 + +G00X74270Y75039 +M15 +G01X74270Y45039 +G02X64270Y35039I-10000J0 +G01X34270Y35039 +G02X24270Y45039I0J10000 +G01X24270Y75039 +G02X34270Y85039I10000J0 +G01X64270Y85039 +G02X74270Y75039I0J-10000 +M16 +G05 + +G00X38204Y42206 +M15 +G01X13451Y42206 +G01X13451Y13596 +G01X38204Y13596 +G01X38204Y42206 +M16 +G05 + +G00X92701Y12632 +M15 +G03X92701Y12632I-12546J0 +M16 +G05 + +G00X60277Y65000 +M15 +G03X60277Y65000I-10277J0 +M16 +G05 + +G00X50000Y65000 +M15 +G01X50000Y71459 +G03X56260Y63409I0J-6459 +G01X50000Y65000 +M16 +G05 + +M30 diff --git a/tests/expects/dxf_save_mousebites.gtl b/tests/expects/dxf_save_mousebites.gtl index 282234d..64cc6d8 100644 --- a/tests/expects/dxf_save_mousebites.gtl +++ b/tests/expects/dxf_save_mousebites.gtl @@ -5,24 +5,578 @@ G75* %LPD*% D10* -X10000Y90000D03* -X10000Y80000D03* -X10000Y70000D03* -X10000Y60000D03* -X10000Y50000D03* -X10000Y40000D03* -X10000Y30000D03* -X10000Y20000D03* -X10000Y10000D03* - -X50000Y90000D03* -X50000Y80000D03* -X50000Y70000D03* -X50000Y60000D03* -X50000Y50000D03* -X50000Y40000D03* -X50000Y30000D03* -X50000Y20000D03* -X50000Y10000D03* +X800000Y850000D03* +X800000Y836000D03* +X800000Y822000D03* +X800000Y808000D03* +X800000Y794000D03* +X800000Y780000D03* +X800000Y766000D03* +X800000Y752000D03* +X800000Y738000D03* +X800000Y724000D03* +X800000Y710000D03* +X800000Y696000D03* +X800000Y682000D03* +X800000Y668000D03* +X800000Y654000D03* +X800000Y640000D03* +X800000Y626000D03* +X800000Y612000D03* +X800000Y598000D03* +X800000Y584000D03* +X800000Y570000D03* +X800000Y556000D03* +X800000Y542000D03* +X800000Y528000D03* +X800000Y514000D03* +X800000Y500000D03* +X800000Y486000D03* +X800000Y472000D03* +X800000Y458000D03* +X800000Y444000D03* +X800000Y430000D03* +X800000Y416000D03* +X800000Y402000D03* +X800000Y388000D03* +X800000Y374000D03* +X800000Y360000D03* + +X900000Y850000D03* +X900000Y836000D03* +X900000Y822000D03* +X900000Y808000D03* +X900000Y794000D03* +X900000Y780000D03* +X900000Y766000D03* +X900000Y752000D03* +X900000Y738000D03* +X900000Y724000D03* +X900000Y710000D03* +X900000Y696000D03* +X900000Y682000D03* +X900000Y668000D03* +X900000Y654000D03* +X900000Y640000D03* +X900000Y626000D03* +X900000Y612000D03* +X900000Y598000D03* +X900000Y584000D03* +X900000Y570000D03* +X900000Y556000D03* +X900000Y542000D03* +X900000Y528000D03* +X900000Y514000D03* +X900000Y500000D03* +X900000Y486000D03* +X900000Y472000D03* +X900000Y458000D03* +X900000Y444000D03* +X900000Y430000D03* +X900000Y416000D03* +X900000Y402000D03* +X900000Y388000D03* +X900000Y374000D03* +X900000Y360000D03* + +X200000Y329390D03* +X214000Y329390D03* +X228000Y329390D03* +X242000Y329390D03* +X256000Y329390D03* +X270000Y329390D03* +X284000Y329390D03* +X298000Y329390D03* +X312000Y329390D03* +X325827Y329217D03* +X325827Y315217D03* +X325827Y301217D03* +X325827Y287217D03* +X325827Y273217D03* +X325827Y259217D03* +X325827Y245217D03* +X325827Y231217D03* +X325827Y217217D03* +X325827Y203217D03* +X325827Y189217D03* + +X400000Y0D03* +X386000Y0D03* +X372000Y0D03* +X358000Y0D03* +X344000Y0D03* +X330000Y0D03* +X316000Y0D03* +X302000Y0D03* +X288000Y0D03* +X274000Y0D03* +X260000Y0D03* +X246000Y0D03* +X232000Y0D03* +X218000Y0D03* +X204000Y0D03* +X190000Y0D03* +X176000Y0D03* +X162000Y0D03* +X148000Y0D03* +X134000Y0D03* +X120000Y0D03* +X106000Y0D03* +X92009Y320D03* +X78177Y2410D03* +X64773Y6410D03* +X52057Y12242D03* +X40280Y19790D03* +X29672Y28909D03* +X20440Y39418D03* +X12764Y51113D03* +X6796Y63764D03* +X2652Y77125D03* +X412Y90933D03* +X0Y104920D03* +X0Y118920D03* +X0Y132920D03* +X0Y146920D03* +X0Y160920D03* +X0Y174920D03* +X0Y188920D03* +X0Y202920D03* +X0Y216920D03* +X0Y230920D03* +X0Y244920D03* +X0Y258920D03* +X0Y272920D03* +X0Y286920D03* +X0Y300920D03* +X0Y314920D03* +X0Y328920D03* +X0Y342920D03* +X0Y356920D03* +X0Y370920D03* +X0Y384920D03* +X0Y398920D03* +X834Y412884D03* +X3602Y426596D03* +X8256Y439788D03* +X14706Y452201D03* +X22825Y463592D03* +X32454Y473739D03* +X43404Y482444D03* +X55463Y489534D03* +X68392Y494873D03* +X81940Y498356D03* +X95842Y499914D03* +X109841Y500000D03* +X123841Y500000D03* +X137841Y500000D03* +X151841Y500000D03* +X165841Y500000D03* +X179841Y500000D03* +X193841Y500000D03* +X207841Y500000D03* +X221841Y500000D03* +X235841Y500000D03* +X249841Y500000D03* +X263841Y500000D03* +X277841Y500000D03* +X291841Y500000D03* +X305841Y500000D03* +X319841Y500000D03* +X333841Y500000D03* +X347841Y500000D03* +X361841Y500000D03* +X375841Y500000D03* +X389841Y500000D03* +X403840Y499926D03* +X417746Y498413D03* +X431305Y494974D03* +X444252Y489676D03* +X456333Y482623D03* +X467311Y473954D03* +X476972Y463838D03* +X485127Y452472D03* +X491617Y440080D03* +X496313Y426903D03* +X499125Y413200D03* +X500000Y399239D03* +X500000Y385239D03* +X500000Y371239D03* +X500000Y357239D03* +X500000Y343239D03* +X500000Y329239D03* +X500000Y315239D03* +X500000Y301239D03* +X500000Y287239D03* +X500000Y273239D03* +X500000Y259239D03* +X500000Y245239D03* +X500000Y231239D03* +X500000Y217239D03* +X500000Y203239D03* +X500000Y189239D03* +X500000Y175239D03* +X500000Y161239D03* +X500000Y147239D03* +X500000Y133239D03* +X500000Y119239D03* +X500000Y105239D03* +X499616Y91250D03* +X497421Y77435D03* +X493319Y64061D03* +X487391Y51391D03* +X479753Y39672D03* +X470554Y29133D03* +X459975Y19981D03* +X448222Y12395D03* +X435525Y6523D03* +X422134Y2480D03* +X408309Y346D03* + +X742704Y750394D03* +X742704Y736394D03* +X742704Y722394D03* +X742704Y708394D03* +X742704Y694394D03* +X742704Y680394D03* +X742704Y666394D03* +X742704Y652394D03* +X742704Y638394D03* +X742704Y624394D03* +X742704Y610394D03* +X742704Y596394D03* +X742704Y582394D03* +X742704Y568394D03* +X742704Y554394D03* +X742704Y540394D03* +X742704Y526394D03* +X742704Y512394D03* +X742704Y498394D03* +X742704Y484394D03* +X742704Y470394D03* +X742704Y456394D03* +X742384Y442402D03* +X740294Y428571D03* +X736294Y415167D03* +X730462Y402451D03* +X722914Y390674D03* +X713795Y380066D03* +X703286Y370834D03* +X691591Y363158D03* +X678940Y357190D03* +X665579Y353045D03* +X651771Y350806D03* +X637784Y350394D03* +X623784Y350394D03* +X609784Y350394D03* +X595784Y350394D03* +X581784Y350394D03* +X567784Y350394D03* +X553784Y350394D03* +X539784Y350394D03* +X525784Y350394D03* +X511784Y350394D03* +X497784Y350394D03* +X483784Y350394D03* +X469784Y350394D03* +X455784Y350394D03* +X441784Y350394D03* +X427784Y350394D03* +X413784Y350394D03* +X399784Y350394D03* +X385784Y350394D03* +X371784Y350394D03* +X357784Y350394D03* +X343784Y350394D03* +X329820Y351227D03* +X316108Y353996D03* +X302916Y358650D03* +X290503Y365100D03* +X279112Y373219D03* +X268965Y382848D03* +X260261Y393798D03* +X253170Y405856D03* +X247831Y418786D03* +X244348Y432334D03* +X242791Y446236D03* +X242704Y460235D03* +X242704Y474235D03* +X242704Y488235D03* +X242704Y502235D03* +X242704Y516235D03* +X242704Y530235D03* +X242704Y544235D03* +X242704Y558235D03* +X242704Y572235D03* +X242704Y586235D03* +X242704Y600235D03* +X242704Y614235D03* +X242704Y628235D03* +X242704Y642235D03* +X242704Y656235D03* +X242704Y670235D03* +X242704Y684235D03* +X242704Y698235D03* +X242704Y712235D03* +X242704Y726235D03* +X242704Y740235D03* +X242778Y754234D03* +X244291Y768140D03* +X247731Y781699D03* +X253028Y794646D03* +X260081Y806727D03* +X268750Y817705D03* +X278866Y827366D03* +X290232Y835521D03* +X302624Y842011D03* +X315801Y846707D03* +X329504Y849519D03* +X343465Y850394D03* +X357465Y850394D03* +X371465Y850394D03* +X385465Y850394D03* +X399465Y850394D03* +X413465Y850394D03* +X427465Y850394D03* +X441465Y850394D03* +X455465Y850394D03* +X469465Y850394D03* +X483465Y850394D03* +X497465Y850394D03* +X511465Y850394D03* +X525465Y850394D03* +X539465Y850394D03* +X553465Y850394D03* +X567465Y850394D03* +X581465Y850394D03* +X595465Y850394D03* +X609465Y850394D03* +X623465Y850394D03* +X637465Y850394D03* +X651454Y850010D03* +X665269Y847815D03* +X678643Y843713D03* +X691313Y837785D03* +X703032Y830147D03* +X713571Y820948D03* +X722723Y810369D03* +X730309Y798616D03* +X736181Y785919D03* +X740224Y772528D03* +X742358Y758703D03* + +X382038Y422062D03* +X368038Y422062D03* +X354038Y422062D03* +X340038Y422062D03* +X326038Y422062D03* +X312038Y422062D03* +X298038Y422062D03* +X284038Y422062D03* +X270038Y422062D03* +X256038Y422062D03* +X242038Y422062D03* +X228038Y422062D03* +X214038Y422062D03* +X200038Y422062D03* +X186038Y422062D03* +X172038Y422062D03* +X158038Y422062D03* +X144038Y422062D03* +X134512Y417588D03* +X134512Y403588D03* +X134512Y389588D03* +X134512Y375588D03* +X134512Y361588D03* +X134512Y347588D03* +X134512Y333588D03* +X134512Y319588D03* +X134512Y305588D03* +X134512Y291588D03* +X134512Y277588D03* +X134512Y263588D03* +X134512Y249588D03* +X134512Y235588D03* +X134512Y221588D03* +X134512Y207588D03* +X134512Y193588D03* +X134512Y179588D03* +X134512Y165588D03* +X134512Y151588D03* +X134512Y137588D03* +X146884Y135960D03* +X160884Y135960D03* +X174884Y135960D03* +X188884Y135960D03* +X202884Y135960D03* +X216884Y135960D03* +X230884Y135960D03* +X244884Y135960D03* +X258884Y135960D03* +X272884Y135960D03* +X286884Y135960D03* +X300884Y135960D03* +X314884Y135960D03* +X328884Y135960D03* +X342884Y135960D03* +X356884Y135960D03* +X370884Y135960D03* +X382038Y138807D03* +X382038Y152807D03* +X382038Y166807D03* +X382038Y180807D03* +X382038Y194807D03* +X382038Y208807D03* +X382038Y222807D03* +X382038Y236807D03* +X382038Y250807D03* +X382038Y264807D03* +X382038Y278807D03* +X382038Y292807D03* +X382038Y306807D03* +X382038Y320807D03* +X382038Y334807D03* +X382038Y348807D03* +X382038Y362807D03* +X382038Y376807D03* +X382038Y390807D03* +X382038Y404807D03* +X382038Y418807D03* + +X927009Y126316D03* +X926228Y140287D03* +X923897Y154085D03* +X920044Y167536D03* +X914717Y180475D03* +X907982Y192741D03* +X899924Y204180D03* +X890641Y214651D03* +X880251Y224022D03* +X868881Y232179D03* +X856674Y239019D03* +X843781Y244457D03* +X830363Y248425D03* +X816586Y250874D03* +X802622Y251774D03* +X788645Y251114D03* +X774828Y248901D03* +X761344Y245164D03* +X748360Y239948D03* +X736037Y233319D03* +X724529Y225358D03* +X713979Y216166D03* +X704519Y205856D03* +X696265Y194557D03* +X689321Y182409D03* +X683773Y169563D03* +X679689Y156179D03* +X677122Y142424D03* +X676102Y128469D03* +X676642Y114486D03* +X678737Y100651D03* +X682358Y87135D03* +X687463Y74107D03* +X693986Y61728D03* +X701847Y50152D03* +X710949Y39524D03* +X721177Y29975D03* +X732405Y21625D03* +X744493Y14576D03* +X757291Y8918D03* +X770639Y4720D03* +X784372Y2035D03* +X798318Y895D03* +X812304Y1316D03* +X826157Y3291D03* +X839703Y6797D03* +X852775Y11789D03* +X865210Y18206D03* +X876852Y25968D03* +X887558Y34978D03* +X897195Y45124D03* +X905641Y56280D03* +X912793Y68307D03* +X918560Y81056D03* +X922873Y94367D03* +X925676Y108077D03* +X926935Y122013D03* + +X602773Y650000D03* +X601821Y663957D03* +X598982Y677655D03* +X594309Y690841D03* +X587889Y703270D03* +X579841Y714712D03* +X570313Y724955D03* +X559483Y733809D03* +X547550Y741111D03* +X534737Y746724D03* +X521280Y750545D03* +X507428Y752504D03* +X493439Y752563D03* +X479572Y750722D03* +X466083Y747015D03* +X453222Y741510D03* +X441228Y734310D03* +X430323Y725547D03* +X420709Y715385D03* +X412565Y704012D03* +X406040Y691637D03* +X401256Y678491D03* +X398301Y664818D03* +X397231Y650870D03* +X398065Y636905D03* +X400788Y623184D03* +X405348Y609959D03* +X411663Y597476D03* +X419614Y585966D03* +X429055Y575643D03* +X439810Y566697D03* +X451680Y559295D03* +X464446Y553573D03* +X477870Y549638D03* +X491705Y547563D03* +X505693Y547385D03* +X519575Y549109D03* +X533095Y552702D03* +X546002Y558098D03* +X558056Y565196D03* +X569035Y573866D03* +X578734Y583946D03* +X586975Y595251D03* +X593605Y607569D03* +X598500Y620674D03* +X601570Y634322D03* +X602758Y648261D03* + +X500000Y650000D03* +X500000Y664000D03* +X500000Y678000D03* +X500000Y692000D03* +X500000Y706000D03* +X494599Y714366D03* +X480883Y711699D03* +X468062Y706144D03* +X456736Y697962D03* +X447434Y687536D03* +X440591Y675353D03* +X436529Y661984D03* +X435437Y648054D03* +X437366Y634216D03* +X442226Y621115D03* +X449789Y609367D03* +X459702Y599520D03* +X471501Y592035D03* +X484633Y587262D03* +X498484Y585425D03* +X512407Y586610D03* +X525748Y590761D03* +X537885Y597685D03* +X548249Y607056D03* +X556356Y618437D03* +X561825Y631294D03* +X551844Y636823D03* +X538276Y640271D03* +X524707Y643720D03* +X511139Y647169D03* M02* diff --git a/tests/expects/dxf_save_mousebites.txt b/tests/expects/dxf_save_mousebites.txt index e82825a..4a64514 100644 --- a/tests/expects/dxf_save_mousebites.txt +++ b/tests/expects/dxf_save_mousebites.txt @@ -7,24 +7,578 @@ T01C0.500 G90 M71 T01 -X1000Y9000 -X1000Y8000 -X1000Y7000 -X1000Y6000 -X1000Y5000 -X1000Y4000 -X1000Y3000 -X1000Y2000 -X1000Y1000 - -X5000Y9000 -X5000Y8000 -X5000Y7000 -X5000Y6000 -X5000Y5000 -X5000Y4000 -X5000Y3000 -X5000Y2000 -X5000Y1000 +X80000Y85000 +X80000Y83600 +X80000Y82200 +X80000Y80800 +X80000Y79400 +X80000Y78000 +X80000Y76600 +X80000Y75200 +X80000Y73800 +X80000Y72400 +X80000Y71000 +X80000Y69600 +X80000Y68200 +X80000Y66800 +X80000Y65400 +X80000Y64000 +X80000Y62600 +X80000Y61200 +X80000Y59800 +X80000Y58400 +X80000Y57000 +X80000Y55600 +X80000Y54200 +X80000Y52800 +X80000Y51400 +X80000Y50000 +X80000Y48600 +X80000Y47200 +X80000Y45800 +X80000Y44400 +X80000Y43000 +X80000Y41600 +X80000Y40200 +X80000Y38800 +X80000Y37400 +X80000Y36000 + +X90000Y85000 +X90000Y83600 +X90000Y82200 +X90000Y80800 +X90000Y79400 +X90000Y78000 +X90000Y76600 +X90000Y75200 +X90000Y73800 +X90000Y72400 +X90000Y71000 +X90000Y69600 +X90000Y68200 +X90000Y66800 +X90000Y65400 +X90000Y64000 +X90000Y62600 +X90000Y61200 +X90000Y59800 +X90000Y58400 +X90000Y57000 +X90000Y55600 +X90000Y54200 +X90000Y52800 +X90000Y51400 +X90000Y50000 +X90000Y48600 +X90000Y47200 +X90000Y45800 +X90000Y44400 +X90000Y43000 +X90000Y41600 +X90000Y40200 +X90000Y38800 +X90000Y37400 +X90000Y36000 + +X20000Y32939 +X21400Y32939 +X22800Y32939 +X24200Y32939 +X25600Y32939 +X27000Y32939 +X28400Y32939 +X29800Y32939 +X31200Y32939 +X32583Y32922 +X32583Y31522 +X32583Y30122 +X32583Y28722 +X32583Y27322 +X32583Y25922 +X32583Y24522 +X32583Y23122 +X32583Y21722 +X32583Y20322 +X32583Y18922 + +X40000Y0 +X38600Y0 +X37200Y0 +X35800Y0 +X34400Y0 +X33000Y0 +X31600Y0 +X30200Y0 +X28800Y0 +X27400Y0 +X26000Y0 +X24600Y0 +X23200Y0 +X21800Y0 +X20400Y0 +X19000Y0 +X17600Y0 +X16200Y0 +X14800Y0 +X13400Y0 +X12000Y0 +X10600Y0 +X9201Y32 +X7818Y241 +X6477Y641 +X5206Y1224 +X4028Y1979 +X2967Y2891 +X2044Y3942 +X1276Y5111 +X680Y6376 +X265Y7712 +X41Y9093 +X0Y10492 +X0Y11892 +X0Y13292 +X0Y14692 +X0Y16092 +X0Y17492 +X0Y18892 +X0Y20292 +X0Y21692 +X0Y23092 +X0Y24492 +X0Y25892 +X0Y27292 +X0Y28692 +X0Y30092 +X0Y31492 +X0Y32892 +X0Y34292 +X0Y35692 +X0Y37092 +X0Y38492 +X0Y39892 +X83Y41288 +X360Y42660 +X826Y43979 +X1471Y45220 +X2282Y46359 +X3245Y47374 +X4340Y48244 +X5546Y48953 +X6839Y49487 +X8194Y49836 +X9584Y49991 +X10984Y50000 +X12384Y50000 +X13784Y50000 +X15184Y50000 +X16584Y50000 +X17984Y50000 +X19384Y50000 +X20784Y50000 +X22184Y50000 +X23584Y50000 +X24984Y50000 +X26384Y50000 +X27784Y50000 +X29184Y50000 +X30584Y50000 +X31984Y50000 +X33384Y50000 +X34784Y50000 +X36184Y50000 +X37584Y50000 +X38984Y50000 +X40384Y49993 +X41775Y49841 +X43131Y49497 +X44425Y48968 +X45633Y48262 +X46731Y47395 +X47697Y46384 +X48513Y45247 +X49162Y44008 +X49631Y42690 +X49912Y41320 +X50000Y39924 +X50000Y38524 +X50000Y37124 +X50000Y35724 +X50000Y34324 +X50000Y32924 +X50000Y31524 +X50000Y30124 +X50000Y28724 +X50000Y27324 +X50000Y25924 +X50000Y24524 +X50000Y23124 +X50000Y21724 +X50000Y20324 +X50000Y18924 +X50000Y17524 +X50000Y16124 +X50000Y14724 +X50000Y13324 +X50000Y11924 +X50000Y10524 +X49962Y9125 +X49742Y7743 +X49332Y6406 +X48739Y5139 +X47975Y3967 +X47055Y2913 +X45997Y1998 +X44822Y1239 +X43553Y652 +X42213Y248 +X40831Y35 + +X74270Y75039 +X74270Y73639 +X74270Y72239 +X74270Y70839 +X74270Y69439 +X74270Y68039 +X74270Y66639 +X74270Y65239 +X74270Y63839 +X74270Y62439 +X74270Y61039 +X74270Y59639 +X74270Y58239 +X74270Y56839 +X74270Y55439 +X74270Y54039 +X74270Y52639 +X74270Y51239 +X74270Y49839 +X74270Y48439 +X74270Y47039 +X74270Y45639 +X74238Y44240 +X74029Y42857 +X73629Y41517 +X73046Y40245 +X72291Y39067 +X71380Y38007 +X70329Y37083 +X69159Y36316 +X67894Y35719 +X66558Y35305 +X65177Y35081 +X63778Y35039 +X62378Y35039 +X60978Y35039 +X59578Y35039 +X58178Y35039 +X56778Y35039 +X55378Y35039 +X53978Y35039 +X52578Y35039 +X51178Y35039 +X49778Y35039 +X48378Y35039 +X46978Y35039 +X45578Y35039 +X44178Y35039 +X42778Y35039 +X41378Y35039 +X39978Y35039 +X38578Y35039 +X37178Y35039 +X35778Y35039 +X34378Y35039 +X32982Y35123 +X31611Y35400 +X30292Y35865 +X29050Y36510 +X27911Y37322 +X26896Y38285 +X26026Y39380 +X25317Y40586 +X24783Y41879 +X24435Y43233 +X24279Y44624 +X24270Y46023 +X24270Y47423 +X24270Y48823 +X24270Y50223 +X24270Y51623 +X24270Y53023 +X24270Y54423 +X24270Y55823 +X24270Y57223 +X24270Y58623 +X24270Y60023 +X24270Y61423 +X24270Y62823 +X24270Y64223 +X24270Y65623 +X24270Y67023 +X24270Y68423 +X24270Y69823 +X24270Y71223 +X24270Y72623 +X24270Y74023 +X24278Y75423 +X24429Y76814 +X24773Y78170 +X25303Y79465 +X26008Y80673 +X26875Y81771 +X27887Y82737 +X29023Y83552 +X30262Y84201 +X31580Y84671 +X32950Y84952 +X34347Y85039 +X35747Y85039 +X37147Y85039 +X38547Y85039 +X39947Y85039 +X41347Y85039 +X42747Y85039 +X44147Y85039 +X45547Y85039 +X46947Y85039 +X48347Y85039 +X49747Y85039 +X51147Y85039 +X52547Y85039 +X53947Y85039 +X55347Y85039 +X56747Y85039 +X58147Y85039 +X59547Y85039 +X60947Y85039 +X62347Y85039 +X63747Y85039 +X65145Y85001 +X66527Y84781 +X67864Y84371 +X69131Y83778 +X70303Y83015 +X71357Y82095 +X72272Y81037 +X73031Y79862 +X73618Y78592 +X74022Y77253 +X74236Y75870 + +X38204Y42206 +X36804Y42206 +X35404Y42206 +X34004Y42206 +X32604Y42206 +X31204Y42206 +X29804Y42206 +X28404Y42206 +X27004Y42206 +X25604Y42206 +X24204Y42206 +X22804Y42206 +X21404Y42206 +X20004Y42206 +X18604Y42206 +X17204Y42206 +X15804Y42206 +X14404Y42206 +X13451Y41759 +X13451Y40359 +X13451Y38959 +X13451Y37559 +X13451Y36159 +X13451Y34759 +X13451Y33359 +X13451Y31959 +X13451Y30559 +X13451Y29159 +X13451Y27759 +X13451Y26359 +X13451Y24959 +X13451Y23559 +X13451Y22159 +X13451Y20759 +X13451Y19359 +X13451Y17959 +X13451Y16559 +X13451Y15159 +X13451Y13759 +X14688Y13596 +X16088Y13596 +X17488Y13596 +X18888Y13596 +X20288Y13596 +X21688Y13596 +X23088Y13596 +X24488Y13596 +X25888Y13596 +X27288Y13596 +X28688Y13596 +X30088Y13596 +X31488Y13596 +X32888Y13596 +X34288Y13596 +X35688Y13596 +X37088Y13596 +X38204Y13881 +X38204Y15281 +X38204Y16681 +X38204Y18081 +X38204Y19481 +X38204Y20881 +X38204Y22281 +X38204Y23681 +X38204Y25081 +X38204Y26481 +X38204Y27881 +X38204Y29281 +X38204Y30681 +X38204Y32081 +X38204Y33481 +X38204Y34881 +X38204Y36281 +X38204Y37681 +X38204Y39081 +X38204Y40481 +X38204Y41881 + +X92701Y12632 +X92623Y14029 +X92390Y15408 +X92004Y16754 +X91472Y18048 +X90798Y19274 +X89992Y20418 +X89064Y21465 +X88025Y22402 +X86888Y23218 +X85667Y23902 +X84378Y24446 +X83036Y24842 +X81659Y25087 +X80262Y25177 +X78865Y25111 +X77483Y24890 +X76134Y24516 +X74836Y23995 +X73604Y23332 +X72453Y22536 +X71398Y21617 +X70452Y20586 +X69626Y19456 +X68932Y18241 +X68377Y16956 +X67969Y15618 +X67712Y14242 +X67610Y12847 +X67664Y11449 +X67874Y10065 +X68236Y8714 +X68746Y7411 +X69399Y6173 +X70185Y5015 +X71095Y3952 +X72118Y2997 +X73241Y2162 +X74449Y1458 +X75729Y892 +X77064Y472 +X78437Y203 +X79832Y90 +X81230Y132 +X82616Y329 +X83970Y680 +X85278Y1179 +X86521Y1821 +X87685Y2597 +X88756Y3498 +X89719Y4512 +X90564Y5628 +X91279Y6831 +X91856Y8106 +X92287Y9437 +X92568Y10808 +X92693Y12201 + +X60277Y65000 +X60182Y66396 +X59898Y67765 +X59431Y69084 +X58789Y70327 +X57984Y71471 +X57031Y72495 +X55948Y73381 +X54755Y74111 +X53474Y74672 +X52128Y75055 +X50743Y75250 +X49344Y75256 +X47957Y75072 +X46608Y74701 +X45322Y74151 +X44123Y73431 +X43032Y72555 +X42071Y71539 +X41256Y70401 +X40604Y69164 +X40126Y67849 +X39830Y66482 +X39723Y65087 +X39807Y63691 +X40079Y62318 +X40535Y60996 +X41166Y59748 +X41961Y58597 +X42905Y57564 +X43981Y56670 +X45168Y55929 +X46445Y55357 +X47787Y54964 +X49170Y54756 +X50569Y54739 +X51958Y54911 +X53310Y55270 +X54600Y55810 +X55806Y56520 +X56903Y57387 +X57873Y58395 +X58698Y59525 +X59360Y60757 +X59850Y62067 +X60157Y63432 +X60276Y64826 + +X50000Y65000 +X50000Y66400 +X50000Y67800 +X50000Y69200 +X50000Y70600 +X49460Y71437 +X48088Y71170 +X46806Y70614 +X45674Y69796 +X44743Y68754 +X44059Y67535 +X43653Y66198 +X43544Y64805 +X43737Y63422 +X44223Y62112 +X44979Y60937 +X45970Y59952 +X47150Y59203 +X48463Y58726 +X49848Y58543 +X51241Y58661 +X52575Y59076 +X53789Y59768 +X54825Y60706 +X55636Y61844 +X56182Y63129 +X55184Y63682 +X53828Y64027 +X52471Y64372 +X51114Y64717 M30 diff --git a/tests/expects/dxf_to_inch.gtl b/tests/expects/dxf_to_inch.gtl index aa862bf..f838214 100644 --- a/tests/expects/dxf_to_inch.gtl +++ b/tests/expects/dxf_to_inch.gtl @@ -6,36 +6,88 @@ G75* %LPD*% D10* G01* -X35433Y0D02* +X314961Y334646D02* G75* G01* -X3937Y0D01* +X314961Y137795D01* +G01* +X354331Y334646D02* +G75* +G01* +X354331Y137795D01* +G01* +X78740Y129681D02* +G75* +G01* +X128278Y129681D01* +G01* +X128278Y70253D01* +G01* +X157480Y0D02* +G75* +G01* +X39370Y0D01* G02* -X0Y3937I0J3937D01* +X0Y39370I0J39370D01* G01* -X0Y35433D01* +X0Y157480D01* G02* -X3937Y39370I3937J0D01* +X39370Y196850I39370J0D01* G01* -X35433Y39370D01* +X157480Y196850D01* G02* -X39370Y35433I0J-3937D01* +X196850Y157480I0J-39370D01* G01* -X39370Y3937D01* +X196850Y39370D01* G02* -X35433Y0I-3937J0D01* +X157480Y0I-39370J0D01* G01* -X3610Y29570D02* +X292403Y295431D02* G75* +G01* +X292403Y177320D01* G02* -X1573Y28756I-1181J0D01* +X253033Y137950I-39370J0D01* G01* -X2429Y29570D01* +X134923Y137950D01* +G02* +X95553Y177320I0J39370D01* G01* -X3610Y29570D01* +X95553Y295431D01* +G02* +X134923Y334801I39370J0D01* +G01* +X253033Y334801D01* +G02* +X292403Y295431I0J-39370D01* G01* -X3610Y19685D02* +X150409Y166166D02* +G75* +G01* +X52957Y166166D01* +G01* +X52957Y53528D01* +G01* +X150409Y53528D01* +G01* +X150409Y166166D01* +G01* +X364964Y49731D02* +G75* +G03* +X364964Y49731I-49395J0D01* +G01* +X237312Y255906D02* G75* G03* -X3610Y19685I-1181J0D01* +X237312Y255906I-40462J0D01* +G01* +X196850Y255906D02* +G75* +G01* +X196850Y281336D01* +G03* +X221497Y249641I0J-25430D01* +G01* +X196850Y255906D01* M02* diff --git a/tests/test_dxf.py b/tests/test_dxf.py index 31589da..3d4d28e 100644 --- a/tests/test_dxf.py +++ b/tests/test_dxf.py @@ -19,7 +19,6 @@ class TestExcellon(unittest.TestCase): cls.OUTPREFIX = 'dxf_' cls.METRIC_FILE = os.path.join(cls.INDIR, 'ref_dxf_metric.dxf') cls.INCH_FILE = os.path.join(cls.INDIR, 'ref_dxf_inch.dxf') - cls.MOUSEBITES_FILE = os.path.join(cls.INDIR, 'ref_dxf_mousebites.dxf') try: os.mkdir(cls.OUTDIR) except FileExistsError: @@ -36,6 +35,7 @@ class TestExcellon(unittest.TestCase): outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'save_line.gtl') dxf = gerberex.read(self.METRIC_FILE) dxf.draw_mode = dxf.DM_LINE + dxf.width = 0.2 dxf.write(outfile) self._checkResult(outfile) @@ -46,23 +46,41 @@ class TestExcellon(unittest.TestCase): dxf.write(outfile) self._checkResult(outfile) + def test_save_fill_simple(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'save_fill_simple.gtl') + dxf = gerberex.read(self.METRIC_FILE) + dxf.draw_mode = dxf.DM_FILL + dxf.fill_mode = dxf.FM_SIMPLE + dxf.write(outfile) + self._checkResult(outfile) + def test_save_mousebites(self): outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'save_mousebites.gtl') - dxf = gerberex.read(self.MOUSEBITES_FILE) + dxf = gerberex.read(self.METRIC_FILE) dxf.draw_mode = dxf.DM_MOUSE_BITES dxf.width = 0.5 - dxf.pitch = 1 + dxf.pitch = 1.4 dxf.write(outfile) self._checkResult(outfile) def test_save_excellon(self): + outfile = os.path.join( + self.OUTDIR, self.OUTPREFIX + 'save_line.txt') + dxf = gerberex.read(self.METRIC_FILE) + dxf.draw_mode = dxf.DM_LINE + dxf.format = (3,3) + dxf.width = 0.2 + dxf.write(outfile, filetype=dxf.FT_EXCELLON) + self._checkResult(outfile) + + def test_save_excellon_mousebites(self): outfile = os.path.join( self.OUTDIR, self.OUTPREFIX + 'save_mousebites.txt') - dxf = gerberex.read(self.MOUSEBITES_FILE) + dxf = gerberex.read(self.METRIC_FILE) dxf.draw_mode = dxf.DM_MOUSE_BITES - dxf.format = (3,3) + dxf.format = (3, 3) dxf.width = 0.5 - dxf.pitch = 1 + dxf.pitch = 1.4 dxf.write(outfile, filetype=dxf.FT_EXCELLON) self._checkResult(outfile) -- cgit