nophead / NopSCADlib

Library of parts modelled in OpenSCAD and a framework for making projects
GNU General Public License v3.0
1.17k stars 155 forks source link

Generate DXF of a sheet modelled in 3D #271

Closed tpimh closed 7 months ago

tpimh commented 7 months ago

I am trying to generate a DXF for sheet material that needs to be drilled with a conical tool. The rendering is correct, BOM entry gets the correct size and type of sheet, but there's no way to generate DXF from it. What I tried is making a projection of the 3D sheet (that didn't work, because there's nowhere to render the resulting model), and using DXF as the base for render_sheet (that didn't work because mixing 2D and 3D objects is not supported). What is the correct way to achieve what I am trying to do? An example code for reference:

material = PMMA6;
size = [50, 50];
screw_type = M3_cs_cap_screw;

//! Use countersink drill bit to make the holes
module main_assembly() assembly("main") {
    // acrylic sheet
    render_sheet(material, w = size.x, d = size.y) difference() {
        sheet(material, size.x, size.y, 4);
        for (x = [-1, 1])
            for (y = [-1, 1])
                translate([x * 20, y * 20]) {
                    translate_z(3) screw_countersink(screw_type);
                    drill(screw_clearance_radius(screw_type), 6);
                }
    }

    // screws
    for (x = [-1, 1])
        for (y = [-1, 1])
            translate([x * 20, y * 20, 3]) screw(screw_type, 10);
}

image

nophead commented 7 months ago

I think you would have to export a 3D STL and use a CAM program that can handle chamfering. Normally one would use a conical bit and chamfer around the the top of the screw hole, rather than just plunging a countersink bit. That way a single bit can be used for all the chamfering, including any countersinks but you might chamfer the edges as well.

The way I do it is I 2D route the outline and the holes and then use a drill press to add countersinks. I set the depth stop to get them all consistent depth. I haven't tried doing it on my mill yet but I think PyCAM could do it from an STL.

tpimh commented 7 months ago

This is very similar to what I am trying to do, and this is exactly why I want to generate DXF with round holes of screw diameter: projection(cut = false).

nophead commented 7 months ago

If you want the 3D countersinks in the output then you need to make the 3D sheet into an STL. You will get the sheet size on the BOM and an STL to send to the mill.

If you want a 2D DXF of the sheet you could use sheet_2D() to make a DXF without the countersinks and then add them into the assembly view by subtracting them after render_2D_sheet(). Then you just add build instruction to remind you to countersink the holes.

If you want a second DXF with the large holes the size of the countersink top then you could do it with a projection that makes a second DXF with the larger holes and use hidden() to add the render_2D_sheet() of it to the assembly view.

tpimh commented 7 months ago

This sort of works with some minor graphical glitches in preview:

material = PMMA6;
size = [50, 50];
screw_type = M3_cs_cap_screw;

module sheet_dxf() {
    dxf("sheet") difference() {
        sheet_2D(material, size.x, size.y, 4);
        for (x = [-1, 1]) for (y = [-1, 1]) translate([x * 20, y * 20])
            drill(screw_clearance_radius(screw_type), 0);
    }
}

//! Route the sheet with holes, then use drill press with the countersink bit
module main_assembly() assembly("main") {
    // acrylic sheet
    render_sheet(material, w = size.x, d = size.y) difference() {
        render_2D_sheet(material) sheet_dxf();
        for (x = [-1, 1]) for (y = [-1, 1]) translate([x * 20, y * 20, 3])
            screw_countersink(screw_type);
    }

    // screws
    for (x = [-1, 1]) for (y = [-1, 1]) translate([x * 20, y * 20, 3])
            screw(screw_type, 10);
}

Most likely, the graphical issue is caused by applying transparency twice. New code: main Old code: main_old Most importantly, the DXF is now generated (BOM looks correct too): image

nophead commented 7 months ago

For transparent objects to display correctly they have to be drawn after all things behind them, so if you draw the screws first I think it will look better.

BTW, you don't need to specify the dimensions in render_sheet() unless you are using a woven material like carbon fibre.

tpimh commented 7 months ago

Yes, thanks! Now it works fine and looks good.

One more optimization here would probably be storing all the screw coordinates in an array and just iterating over it. Now the coordinates are calculated 3 times: for holes, for countersink holes, for the screws.

tpimh commented 7 months ago

Not sure if it's better or worse, but here it is:

material = PMMA6;
size = [50, 50];
screw_type = M3_cs_cap_screw;

function distribute_screws(x, y) =
  [[-x / 2, -y / 2], [x / 2, -y / 2], [-x / 2, y / 2], [x / 2, y / 2]];
screw_pos = distribute_screws(40, 40);
screw_dep = sheet_thickness(material) / 2;

module sheet_dxf() {
  dxf("sheet") difference() {
    sheet_2D(material, size.x, size.y, 4);
    for (p = screw_pos)
      translate(p) drill(screw_clearance_radius(screw_type), 0);
  }
}

//! Route the sheet with holes for the screws, use drill press with the countersink bit
module main_assembly() assembly("main") {
  // screws
  for (p = screw_pos)
    translate(p) translate_z(screw_dep) screw(screw_type, 10);

  // acrylic sheet
  render_sheet(material) difference() {
    render_2D_sheet(material) sheet_dxf();
    for (p = screw_pos)
      translate(p) translate_z(screw_dep) screw_countersink(screw_type);
  }
}
nophead commented 7 months ago

I usually represent any positions that I need to be repeated by a module that positions its children. I then use it to drill the holes and place the fasteners, etc. I only resort to lists, usually of transforms, when I need to do something more complicated, see butt_box.scad.