Cutout on geometry object failed - fixed for next version

Issue #560 new
nerdunio created an issue

Hi

I try to generate G-Code to cut a PCB outline.

The outline gerber file introduces a small offset because of the trace width which translate to an offset in the final PCB.

Here’s what I tried to eliminate the offset:

  • Use the “Follow” plugin to get the center line of the outline as a new geometry object.
  • Open the “Cutout” tool and select the previously generated “outline_follow” object.
  • Use default parameters (except margin 0.0000) and click “Generate Geometry”.
  • Console:
DEBUG 20220125_185415 ***   Object _cutout has been promised.
[ERROR] Failed.

My configuration

  • win10
  • python 3.9.2
  • FlatCAM Beta (Beta_8.995, c08acc7)

Hope someone can help me with that.

Comments (29)

  1. nerdunio reporter

    Hi Marius,

    The .zip (marius_stanciu-flatcam_beta-51d4f9030d42) from you link points to the commit 51d4f9030d42 in the Beta_8.995 branch.

    I checked out the mentioned branch and made a pull. Now I’m on the latest commit and I have the same issue as stated above.

    I also set up the project from you link, just to be sure I don’t make a mistake. However, I have the same issue here.

  2. nerdunio reporter

    Hi Marius,

    Yes, I did the same.

    Here’ the console output:

    [INFO][MainThread] FlatCAM Starting...
    [DEBUG][MainThread] Win64!
    [DEBUG][MainThread] Application path is C:\desktop\flatcam_beta
    [DEBUG][MainThread] Started in C:\desktop\flatcam_beta
    [DEBUG][MainThread] FlatCAM defaults loaded from: C:\Users\make\AppData\Roaming\FlatCAM\current_defaults_Unstable.FlatConfig
    [DEBUG][MainThread] App.__init__() --> Applied English language.
    [DEBUG][MainThread] MainGUI.__init__() --> UI state restored from QSettings.
    [DEBUG][MainThread] MainGUI.__init__() --> UI layout restored from QSettings. Layout = minimal
    [DEBUG][MainThread] Stardate: 20220126_093821
    [DEBUG][MainThread] TCL Shell has been initialized.
    [DEBUG][MainThread] App.save_project_auto_update() --> updated the interval timeout.
    [DEBUG][MainThread] propagate_defaults()
    [DEBUG][MainThread] Finished creating Object Collection.
    [DEBUG][MainThread] Setting up canvas: 3D
    [DEBUG][MainThread] Finished Canvas initialization in 0.5790972709655762 seconds.
    [DEBUG][MainThread] Finished creating Workers crew.
    [DEBUG][MainThread] Tools are installed.
    [DEBUG][MainThread] Initialization of the Geometry Editor is finished ...
    [DEBUG][MainThread] Initialization of the Excellon Editor is finished ...
    [DEBUG][MainThread] Initialization of the Gerber Editor is finished ...
    [DEBUG][MainThread] Initialization of the GCode Editor is finished ...
    [DEBUG][MainThread] Finished adding FlatCAM Editor's.
    [DEBUG][MainThread] + Adding Exclusion Areas
    [DEBUG][MainThread] Recent items list has been populated.
    [DEBUG][MainThread]  -> Connecting Toolbar Signals       
    [DEBUG][MainThread]  -> Connecting Plugin Toolbar Signals
    [DEBUG][MainThread] Finished connecting Signals.
    [DEBUG][MainThread] END of constructor. Releasing control.
    [DEBUG][MainThread] ... Resistance is futile. You will be assimilated ...
    [DEBUG][MainThread] ... I disagree. While we live and breath, we can be free!
    
    [DEBUG][Dummy-4] open_gerber()
    [DEBUG][Dummy-4] AppObject.new_object()
    [DEBUG][Dummy-4] Calling object constructor...
    [DEBUG][Dummy-4] 0.021004 seconds before initialize().
    [WARNING][Dummy-4] Line ignored (6): %ASAXBY*%
    [DEBUG][Dummy-4] Gerber format found. (%FSLAX23Y23*%)
    [DEBUG][Dummy-4] Gerber format found. Gerber zeros = L (L-omit leading zeros, T-omit trailing zeros, D-no zero supression)
    [DEBUG][Dummy-4] Gerber format found. Coordinates type = Absolute (Absolute or Relative)
    [DEBUG][Dummy-4] Gerber units found = IN
    [WARNING][Dummy-4] Line ignored (9): %OFA0B0*%
    [WARNING][Dummy-4] Line ignored (10): %SFA1.0B1.0*%
    [WARNING][Dummy-4] Line ignored (14): %LNCONTOUR*%
    [WARNING][Dummy-4] Gerber obsolete coordinates type found = Absolute (Absolute or Relative)
    [WARNING][Dummy-4] Gerber obsolete units found = IN
    [WARNING][Dummy-4] Joining 1 polygons.
    [DEBUG][Dummy-4] Union by buffer...
    [WARNING][Dummy-4] Union(buffer) done.
    [DEBUG][Dummy-4] New object with name: detector_contour.gbr. 0.007002 seconds executing initialize().
    [DEBUG][Dummy-4] FlatCAMObj.GerberObject.convert_units()
    [DEBUG][Dummy-4] parseGerber.Gerber.convert_units() --> Factor: 25.4
    [DEBUG][Dummy-4] parseGerber.Gerber.scale()
    [DEBUG][Dummy-4] 0.003000 seconds converting units.
    [DEBUG][Dummy-4] parseGerber.Gerber.bounds()
    [DEBUG][Dummy-4] Moving new object back to main thread.
    [DEBUG][MainThread] on_object_created()
    [DEBUG][MainThread] on_object_created --> OC.append()
    [DEBUG][MainThread] GerberObject.set_ui()
    [DEBUG][MainThread] set_ui --> FlatCAMObj.to_form()
    [DEBUG][MainThread] build_ui--> FlatCAMObj.build_ui()
    [DEBUG][MainThread] parseGerber.Gerber.bounds()
    [DEBUG][MainThread] build_ui--> FlatCAMObj.build_ui()
    [DEBUG][MainThread] register_recent()
    [DEBUG][MainThread]    gerber
    [DEBUG][MainThread]    C:/desktop/flatcam_beta/tests/gerber_files/detector_contour.gbr
    [DEBUG][Dummy-5] plotting_task --> GerberObject.plot()
    [DEBUG][Dummy-5] 0.312000 seconds adding object and plotting.
    [DEBUG][Dummy-4] AppObject.new_object()
    [DEBUG][Dummy-4] Calling object constructor...
    [DEBUG][Dummy-4] 0.020004 seconds before initialize().
    [DEBUG][Dummy-4] New object with name: detector_contour_follow. 0.002000 seconds executing initialize().
    [DEBUG][Dummy-4] camlib.Geometry.bounds()
    [DEBUG][Dummy-4] Moving new object back to main thread.
    [DEBUG][MainThread] on_object_created()
    [DEBUG][MainThread] on_object_created --> OC.append()
    [DEBUG][MainThread] GeometryObject.set_ui()
    [DEBUG][MainThread] set_ui --> FlatCAMObj.to_form()
    [DEBUG][MainThread] camlib.Geometry.bounds()
    [DEBUG][MainThread] build_ui--> FlatCAMObj.build_ui()
    [DEBUG][Dummy-5] 0.039009 seconds adding object and plotting.
    [DEBUG][MainThread] App.on_disable_sel_plot()
    [DEBUG][MainThread] Disabling plots ...
    [DEBUG][Dummy-4] worker_task --> GerberObject.plot()
    [DEBUG][MainThread] CutOut.on_freeform_cutout() is running....
    [DEBUG][MainThread] Object detector_contour_follow_cutout has been promised.
    [DEBUG][Dummy-4] Cutout.on_freeform_cutout() -> Empty geometry.
    [DEBUG] App.PreferencesUIManager.save_defaults()
    [DEBUG][MainThread] propagate_defaults()
    [DEBUG][MainThread] App.save_project_auto_update() --> updated the interval timeout.
    [DEBUG] App.PreferencesUIManager.save_defaults()
    [DEBUG][MainThread] propagate_defaults()
    [DEBUG][MainThread] App.save_project_auto_update() --> updated the interval timeout.
    [DEBUG][MainThread] App.quit_application() --> App Defaults saved.
    [DEBUG][MainThread] App.quit_application() --> App UI state saved.
    

  3. Marius Stanciu

    Hi Manuel,
    Looks like the behavior from before the changes I’ve done. Are you sure you are using the latest commit?
    In any case, can you edit the first post and add the Gerber file that you are using so I can try it myself ?
    Thanks,
    Marius

    LE: Ok, I just seen the behavior on a different Gerber file. No need for the upload, thanks.

  4. nerdunio reporter

    The file is flatcam_beta\tests\gerber_files\detector_contour.gbr

    How can I check that I’m on the latest branch?

    I used git log to check:

  5. Marius Stanciu

    Hi,
    Try the latest commit, do a git pull on the Beta_8.995 branch.
    Should be fixed now.
    Best regards,
    Marius

  6. nerdunio reporter

    Hi,

    I did the pull and now I can generate the cutout.

    However, it seems that the radius correction for the tool diameter is not applied. This means the mill is on the center line.

  7. Marius Stanciu

    That is what the Follow plugin does. Creates a geometry path that follows the center of a trace. The Milling plugin will always cut through the geometry that has as source. Wasn’t that what you wanted?

  8. nerdunio reporter

    Ok, I understand.

    If I select the gerber file and apply the cutout plugin I can define the tool diameter and then the mill cuts the outside of the gerber file geometry. However, the contour of the actual part will be off by the width defined in the gerber file.

    (One approach was to set the width of the gerber file to 0.001mm with the help of the Gerber Editor. This works fine but it is dirty.)

    From working with gerber files I know that the cutout plugin corrects the tool diameter so the mill does not penetrate the gerber.

    I now understand that the cutout plugin behaves differently on geometries. However, it would be great to have a radius correction checkbox or the option to set the tool diameter to 0 if the tool should follow the center line (without radius correction).

  9. Marius Stanciu

    I now understand that the cutout plugin behaves differently on geometries.

    Actually it does not. Tthe Cutout plugin works essentially on geometries, paths if you like. When working with a Gerber object, it first creates a Geometry object that surrounds the Gerber at half the tool diameter and then cut through it. If it works directly on a Geometry object it simply does not have to create a new Geometry around that one and then it just cuts through it as is supposed to do.

  10. Marius Stanciu

    I now understand that the cutout plugin behaves differently on geometries. However, it would be great to have a radius correction checkbox or the option to set the tool diameter to 0 if the tool should follow the center line (without radius correction).

    That can be done only in multiple steps since it is something custom that you want the corners rounded and that will not be conform with your geometry. You could do a Tcl script for that.

  11. Marius Stanciu

    I just made some mods which should also allow what you want.
    With Cutout plugin in Advanced mode, create a Manual Geometry with tool diameter of 0.0. Then on the resulting Geometry object, with it selected, run the Menu → Options → Object Transform plugin (Transformation Plugin). Apply a buffer with negative value of half the tool diameter (with rounded checkbox checked) and you should have your expected result.

    A Tcl script should look like this:
    1. open_gerberthe Gerber outline file
    2. isolate the Gerber outline with a diameter of 0.0 and iso_type 0 (keeps only exterior isolation).
    3. buffer the isolation geometry with half the diameter, negative value
    4. geocutout or cutout the geometry resulted above
    5. cncjob on the above geometry
    6. write_gcode to save the GCode file

    I have not tried a script like that, there may be issues or require some tweaks, but I will help you with any issues you may encounter.

  12. nerdunio reporter

    Thanks for your answers!

    I pulled the latest version.

    I got through the 6 steps with the GUI and the result is the same as I would have used the outline plugin directly on the gerber:

  13. Marius Stanciu

    Hi,
    I’ve done some more updates so you should update your local copy to the latest commit.

    An idea of a script to generate the cutout Geometry that you want is like this:

    cd "D:\\MEGA\\gerb\\Altium D 20.1.11"
    open_gerber "35V3A.GKO" -outname cut_gerber
    isolate cut_gerber -dia 0.0 -iso_type 0 -outname gerber_iso
    ext gerber_iso -outname iso_ext
    buffer iso_ext -dist -0.1
    geocutout iso_ext -dia 0.2 -gapsize 2 -gaps 4 -outname cutout_geo
    plot_all
    

    After that you mill it (either in GUI or with the cncjob Tcl command) and then save the GCode.

    The above assume an Gerber outline with 0.2mm outline thickness. Create a new script in Menu → File → Scripting → New Script. And save it for latter use. Run it… You can omit the loading step (open_gerber command) if the Gerber is already loaded…

  14. nerdunio reporter

    yes, if I use a negative number the geometry disappears.

    Here’s the console output.

    [SUCCESS] Object was buffered...
    DEBUG 20220126_161017 ***   camlib.Geometry.bounds()
    DEBUG 20220126_161017 ***   solid_geometry is None
    DEBUG 20220126_161017 ***   Object changed, updating the bounding box data on self.options
    [SUCCESS] Buffer done...
    

  15. nerdunio reporter

    Thank you for you help so far.

    I will try you script. However, in your example the line width of my gerber outline must be 0.2mm. In some cases the line width is unknown (or cumbersome to look it up for every job).

    What’s the difference between the geometry generated from the gerber outline (2. isolate the Gerber outline with a diameter of 0.0 and iso_type 0 (keeps only exterior isolation) and the geometry of the follow plugin applied to the outline gerber?

    When I apply the buffer to the geometry from the follow plugin I get two traces. Would be great if the buffer object transformation would have the same options (Full, Ext, Int) as the isolation type of the advanced cutout.

    Another possibility would be to set the trace width of the outline gerber to 0.0 from Tcl.

  16. Marius Stanciu

    The problem is with multiple assumptions and impossible way to guess the kind of outline you have. Some people will use as outline to feed into Cutout plugin more complex objects, perhaps with many apertures so it will be very hard unless making a special tool for that. Which is a bit too much for a corner case.

    The problem with using a Follow Geometry is only if the outline is a rectangle because the follow Geometry also will be a rectangle without the rounded corners. We get the rounded corners by buffering something smaller, like the inside of the outline trace. Using the negative tool diameter is a way to obtain that but that will not work with the Follow Geometry.

  17. nerdunio reporter

    ok, I understand.

    I tested you script. The geocutout does not generate a cutout from the cutout_geo geometry.

    geocutout iso_ext -dia 0.2 -gapsize 2 -gaps 4 -outname cutout_geo

  18. Marius Stanciu

    geocutout command works on the iso_ext geometry and the result is the cutout_geo Geometry file.

    LE: BTW, here is how it works in my case:

  19. nerdunio reporter

    Sorry, The geocutout does not generate the cutout_geo geometry from the iso_ext geometry.

  20. nerdunio reporter

    Oh, I see, you machining is in the center of the gerber board outline.

    Here’s what I wan’t to achieve. Note that the trace width is set to 0.001mm.

  21. Marius Stanciu

    You could create the cutout normally, with a margin of 0.0 mm and then compensate the trace width (which you have to know) in the Milling process using the milling Offset feature in the Milling Plugin.

  22. nerdunio reporter

    Hi,

    (about you latest response: I tried but the offset feature will cutout the four segements of the contour)

    I would like to implement the steps of my last response as a flat script. I will either set the trace width of the outline gerber file to 0.001mm or I will compensate the width with the tool diameter.

    open_gerber "detector_contour.gbr" -outname gerber_outline
    geocutout gerber_outline -dia 2.4 -margin 0.0 -gapsize 0.5 -gaps 4 -outname gerber_cutout
    

    Unfortunately, the geocutout does not generate the gerber_cutout geometry.

    The file is again flatcam_beta\tests\gerber_files\detector_contour.gbr

    I pulled the latest commit and here’s the console output.

    [DEBUG][Dummy-4] open_gerber()
    [DEBUG][Dummy-4] AppObject.new_object()
    [DEBUG][Dummy-4] Calling object constructor...
    [DEBUG][Dummy-4] 0.020005 seconds before initialize().
    [WARNING][Dummy-4] Line ignored (6): %ASAXBY*%
    [DEBUG][Dummy-4] Gerber format found. (%FSLAX23Y23*%)
    [DEBUG][Dummy-4] Gerber format found. Gerber zeros = L (L-omit leading zeros, T-omit trailing zeros, D-no zero supression)
    [DEBUG][Dummy-4] Gerber format found. Coordinates type = Absolute (Absolute or Relative)
    [DEBUG][Dummy-4] Gerber units found = IN
    [WARNING][Dummy-4] Line ignored (9): %OFA0B0*%
    [WARNING][Dummy-4] Line ignored (10): %SFA1.0B1.0*%
    [WARNING][Dummy-4] Line ignored (14): %LNCONTOUR*%
    [WARNING][Dummy-4] Gerber obsolete coordinates type found = Absolute (Absolute or Relative)
    [WARNING][Dummy-4] Gerber obsolete units found = IN
    [WARNING][Dummy-4] Joining 1 polygons.
    [DEBUG][Dummy-4] Union by buffer...
    [WARNING][Dummy-4] Union(buffer) done.
    [DEBUG][Dummy-4] New object with name: gerber_outline. 0.009002 seconds executing initialize().
    [DEBUG][Dummy-4] FlatCAMObj.GerberObject.convert_units()
    [DEBUG][Dummy-4] parseGerber.Gerber.convert_units() --> Factor: 25.4
    [DEBUG][Dummy-4] parseGerber.Gerber.scale()
    [DEBUG][Dummy-4] 0.003001 seconds converting units.
    [DEBUG][Dummy-4] parseGerber.Gerber.bounds()
    [DEBUG][Dummy-4] Moving new object back to main thread.
    [DEBUG][MainThread] on_object_created()
    [DEBUG][MainThread] on_object_created --> OC.append()
    [DEBUG][MainThread] GerberObject.set_ui()
    [DEBUG][MainThread] set_ui --> FlatCAMObj.to_form()
    [DEBUG][MainThread] build_ui--> FlatCAMObj.build_ui()
    [DEBUG][MainThread] parseGerber.Gerber.bounds()
    [DEBUG][MainThread] build_ui--> FlatCAMObj.build_ui()
    [DEBUG][MainThread] register_recent()
    [DEBUG][MainThread]    gerber
    [DEBUG][MainThread]    detector_contour.gbr
    [DEBUG][MainThread] Recent items list has been populated.
    [DEBUG][MainThread] TCL command 'TclCommandGeoCutout' executed.
    [DEBUG][Dummy-4] parseGerber.Gerber.bounds()
    [DEBUG][Dummy-4] AppObject.new_object()
    [DEBUG][Dummy-4] Calling object constructor...
    [DEBUG][Dummy-4] 0.020004 seconds before initialize().
    [ERROR][Dummy-4] TclCommandGeoCutout.execute() --> isolation_geometry() got an unexpected keyword argument 'follow'
    [DEBUG][Dummy-4] New object with name: gerber_cutout. 0.000000 seconds executing initialize().
    [DEBUG][Dummy-4] Object (geometry) parsing and/or geometry creation failed.
    [DEBUG][MainThread] TCL command 'TclCommandPlotAll' executed.
    [DEBUG][Dummy-4] Plot_all()
    [DEBUG][Dummy-4] worker_task --> GerberObject.plot()
    

  23. Log in to comment