Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

F5 preview not working correctly - manifild #5010

Closed
rjcarlson49 opened this issue Feb 24, 2024 · 3 comments
Closed

F5 preview not working correctly - manifild #5010

rjcarlson49 opened this issue Feb 24, 2024 · 3 comments

Comments

@rjcarlson49
Copy link

rjcarlson49 commented Feb 24, 2024

Describe the bug
Using manifold, the F5 preview does not seem to work correctly. The display can seem correct from some angles and incorrect in others. The code below is not simple but it is complete except that it uses BOSL2.

Code reproducing the issue

include <BOSL2/std.scad>;
include <BOSL2/rounding.scad>;

$fn = 180;
showRect = false;
showShapes = false;
showBevels = false;
showPoly = false;
showJoin = false;
showHelp = false;

if (showHelp) {
    hex_panel("help");
}
if (showShapes) {
    s0 = glued_circles(d=50, spread=50, tangent=30);
    s1 = circle(30);
    zdistribute(spacing = 20){
        hex_panel(s0, h = 10, frame = 5); 
        hex_panel(s1, h = 10, frame = 5);
    }
}
if (showPoly) {
    s2 = [[0, -40], [0, 40], [30, 20], [60, 40], [60, -40], [30, -20]];
    s1 = [[0, -40], [0, 40], [60, 0]];
    s0 = [[0, -40], [0, 70], [60, 0], [80, 20], [70, -20]];
    zdistribute(spacing = 20){
        hex_panel(s2, h = 10, frame = 5); 
        hex_panel(s0, h = 10, frame = 5); 
        hex_panel(s1, h = 10, frame = 5); 
    }
}
if (showJoin) {
    hex_panel([50, 100, 10], frame = 5, bevel = [FWD,  BACK], anchor = BACK + RIGHT + BOTTOM, orient = RIGHT);
    hex_panel([100, 50, 10], frame = 5, bevel = [LEFT, RIGHT], anchor = FWD + LEFT + BOTTOM, orient = FWD);
}
if (showRect) {
    zdistribute(spacing = 20){
        hex_panel([50, 100, 5], frame = 5);
        hex_panel([50, 100, 5], frame = 5, wall = 5);
        hex_panel([50, 100, 5], frame = 5, spacing = 20);
        hex_panel([50, 100, 5], frame = 10, spacing = 20, wall = 4);
    }
}
if (showBevels) {
    zdistribute(spacing = 20){
        hex_panel([50, 100, 10], frame = 5, bevel = []);
        hex_panel([50, 100, 10], frame = 5, bevel = [LEFT, RIGHT]);
        hex_panel([50, 100, 10], frame = 5, bevel = [FWD,  BACK]);
        hex_panel([50, 100, 10], frame = 5, bevel = [LEFT, RIGHT, FWD, BACK]);
        hex_panel([50, 100, 10], frame = 5, bevel = [LEFT, RIGHT, FWD+BOTTOM, BACK+BOTTOM]);
    }
}

t = .1;
t2 = 2 * t;
tiny = 1/128;

function _honeycomb(shape, spacing=10, hex_wall=1) =
    let(
        hex = hexagon(id=spacing-hex_wall, spin=180/6),
        bounds = pointlist_bounds(shape),
        size = bounds[1] - bounds[0],
        hex_rgn2 = grid_copies(spacing=spacing, size=size, stagger=true, p=hex),
        center = (bounds[0] + bounds[1]) / 2,
        hex_rgn = move(center, p=hex_rgn2),
        ihex_rgn = intersection(hex_rgn, shape),
        out_rgn = difference(shape, ihex_rgn)
    ) out_rgn;

module _honeycomb(shape, spacing=10, hex_wall=1) {
    rgn = _honeycomb(shape, spacing=spacing, hex_wall=hex_wall);
    region(rgn);
}

// Module: hex_panel()
// Usage:
//   hex_panel(shape, frame, [h,] [wall = 1.5,] [spacing = 10,] [bevel,] [anchor = CENTER,] [orient = UP,] [spin = 0])
// Description:
//   Produces a panel with a honeycomb interior. The panel consists of a frame containing
//   a honeycob interior. The frame is laid out in the XY plane with the honeycob interior 
//   and then extruded to the height h. The shape argument defines the outer bounderies of
//   the frame.
//   .
//   The simplest way to define the frame shape is to give a 3D vector in the shape argument.
//   In this case, x and y define a rectangle which is the frame and z is the height (h). 
//   The h argument is ignored in this case.
//   . 
//   The other option is to provide a 2D path as the shape argument. The path must be 
//   non-crossing and is assumed to be closed. 
//   .
//   Enter "help" as the shape argument to echo the synopsis to the console.
//   .
// Arguments:
//   shape = either a path as defined in BOSL2 or a 3D vector in the form [x, y, z]. 
//   if shape == "help" an assert will fail and a synopsis of the module is printed.
//   frame = width of the frame around the honeycomb, required
//   h = thickness of the panel, required when shape is a path.
//   ---
//   wall = thickness of the walls in the honeycomb, Default: 1.5
//   spacing = size of the hex cells in the honeycomb: Default: 10
//   bevel = vector of vectors. Each vector entry must be one of the BOSL2 directional
//   defines RIGHT, LEFT, BACK, or FRONT. BOTTOM may be added to produce a bevel
//   on the bottom of the panel, as in BACK+BOTTOM. Entries MUST be separated by commas.
//   Bevel is allowed only when shape is a simple 3D vector, [x, y, z]. Default: [].
//   anchor = the usual BOSL2 anchors
//   orient = the usual BOSL2 orientations
//   spin = the usual BOSL2 spin
// Example: Rectangular Panels
//   zdistribute(spacing = 20){
//     hex_panel([50, 100, 5], frame = 5);
//     hex_panel([50, 100, 5], frame = 5, wall = 5);
//     hex_panel([50, 100, 5], frame = 5, spacing = 20);
//     hex_panel([50, 100, 5], frame = 10, spacing = 20, wall = 4);
//   }
// Example: Bevel Combinations
//   zdistribute(spacing = 20){
//     hex_panel([50, 100, 10], frame = 5, bevel = []);
//     hex_panel([50, 100, 10], frame = 5, bevel = [LEFT, RIGHT]);
//     hex_panel([50, 100, 10], frame = 5, bevel = [FWD,  BACK]);
//     hex_panel([50, 100, 10], frame = 5, bevel = [LEFT, RIGHT, FWD, BACK]);
//     hex_panel([50, 100, 10], frame = 5, bevel = [LEFT, RIGHT, FWD+BOTTOM, BACK+BOTTOM]);
//  }
// Example: Shapes
//   s0 = glued_circles(d=50, spread=50, tangent=30);
//   s1 = circle(30);
//   zdistribute(spacing = 20){
//     hex_panel(s0, h = 10, frame = 5); 
//     hex_panel(s1, h = 10, frame = 5);
//   }

module hex_panel(
    shape,
    frame, 
    h,
    wall = 1.5, 
    spacing = 10,
    bevel = [],
    anchor = CENTER, 
    orient = UP, 
    spin = 0) 
{
    //d00 = echo("Frame ", frame, "  h ", h, "  shape ", shape);
    d0 = assert(shape!="help", "\n\nhex_panel(shape, frame, [h,] \n    [wall = 1.5,] [spacing = 10,] [bevel,]\n    [anchor = CENTER], [orient = UP,] [spin = 0])\n\n");

    d1 = 
    assert(!is_undef(frame) && frame > 0, "frame must be > 0")
    assert(is_path(shape) || is_vector(shape, 3), "shape must be a path or a 3D vector")
    assert(len(bevel) == 0 || is_vector(shape, 3), "bevel must be used only on rectangular panels")
    assert(is_path(shape) || (shape.x > 0 && shape.y > 0 && shape.z > 0), 
           "shape must be a path or a 3D vector")
    assert(!(in_list(FRONT, bevel) && in_list(FRONT+BOTTOM, bevel)), "conflicting FRONT bevels")
    assert(!(in_list(BACK,  bevel) && in_list(BACK+BOTTOM,  bevel)), "conflicting BACK bevels")
    assert(!(in_list(RIGHT, bevel) && in_list(RIGHT+BOTTOM, bevel)), "conflicting RIGHT bevels")
    assert(!(in_list(LEFT,  bevel) && in_list(LEFT+BOTTOM,  bevel)), "conflicting LEFT bevels");

    shp = is_path(shape) ? shape : square([shape.x, shape.y], center = true);
    ht = is_path(shape) ? h : shape.z;
    
    //d1 = echo("is_path(shape) ", is_path(shape), " Shape ", shp);
    
    bounds = pointlist_bounds(shp);
    sizes = bounds[1] - bounds[0]; // [xsize, ysize]
    //d2 = echo("sizes, h ", sizes, ht);
    centers = (bounds[0] + bounds[1]) / 2;
    
    assert(frame*2 + spacing < sizes[0], "There must be room for at least 1 cell in the honeycomb");
    assert(frame*2 + spacing < sizes[1], "There must be room for at least 1 cell in the honeycomb");
    
    attachable(anchor = anchor, spin = spin, orient = orient, size = [sizes.x, sizes.y, ht]) {
        //d = echo("Bounds, Centers, Sizes ", bounds, centers, sizes);
        if (len(bevel) > 0) {
            intersection() {
                union() {
                    left(centers.x) fwd(centers.y) down(ht/2) 
                    linear_extrude(height = ht) {
                        _honeycomb(shp, spacing = spacing, hex_wall = wall);
            
                        offset_stroke(shp, width=[-frame, 0], closed=true);
                    }

                    for (b = bevel) _bevelWall(shape, b);
                }
                down(ht/2)
                _bevelSolid(shape, bevel);
            }
        } else {
            left(centers.x) fwd(centers.y) down(ht/2) 
            linear_extrude(height = ht) {
                _honeycomb(shp, spacing = spacing, hex_wall = wall);
    
                offset_stroke(shp, width=[-frame, 0], closed=true);
            }
        }
        children();
    } // attachable
}

module _bevelSolid(shape, bevel) {
    tX = in_list(RIGHT,          bevel) ? -shape.z : 0;
    tx = in_list(LEFT,           bevel) ?  shape.z : 0;
    tY = in_list(BACK,           bevel) ? -shape.z : 0;
    ty = in_list(FRONT,          bevel) ?  shape.z : 0;
    bX = in_list(RIGHT + BOTTOM, bevel) ? -shape.z : 0;
    bx = in_list(LEFT  + BOTTOM, bevel) ?  shape.z : 0;
    bY = in_list(BACK  + BOTTOM, bevel) ? -shape.z : 0;
    by = in_list(FRONT + BOTTOM, bevel) ?  shape.z : 0;

    pathB = [[ shape.x/2 + bX,  shape.y/2 + bY], [ shape.x/2 + bX, -shape.y/2 + by], 
             [-shape.x/2 + bx, -shape.y/2 + by], [-shape.x/2 + bx,  shape.y/2 + bY]];
    pathT = [[ shape.x/2 + tX,  shape.y/2 + tY], [ shape.x/2 + tX, -shape.y/2 + ty], 
             [-shape.x/2 + tx, -shape.y/2 + ty], [-shape.x/2 + tx,  shape.y/2 + tY]];
    
    hull() {
        down(tiny) linear_extrude(tiny) polygon(pathB);
        up(shape.z-tiny) linear_extrude(tiny) polygon(pathT);
    }
}

module _bevelWall(shape, bevel) {

    l = bevel.y != 0 ? shape.x : shape.y;
    d = bevel.y != 0 ? shape.y : shape.x;
    zr = bevel.y == -1 ? 180 
       : bevel.y ==  1 ? 0 
       : bevel.x == -1 ? 90 
       : bevel.x ==  1 ? 270 
       : undef;
    xr = bevel.x != 0 && bevel.z < 0 ? 180 : 0;
    yr = bevel.y != 0 && bevel.z < 0 ? 180 : 0;
    
    path = [[-1, 0], [0, 0], [-shape.z, -shape.z], [-shape.z-1, -shape.z]];

    xrot(xr) 
    yrot(yr)
    zrot(zr)
    down(shape.z/2) 
    back(d/2) 
    right(l/2) 
    zrot(90) 
    xrot(-90)
    linear_extrude(l) polygon(path);
}

Screenshots
In a reply

Environment and Version info (please complete the following information):

  • OS: Mac up to date
  • System: iMac M3
  • OpenSCAD Version 2024.02.19
@rjcarlson49
Copy link
Author

This looks OK

Image 2-23-24 at 18 09

This does not

Image 2-23-24 at 18 11

@jordanbrown0
Copy link
Contributor

This is a convexity issue. See the FAQ.

Any of the primitive constructs that can generate a concave polyhedron can have this problem: linear_extrude, rotate_extrude, polyhedron, import, render, and I think minkowski.

In this case I think it's the linear_extrude at line 176. Setting convexity to 5 appears to fix it, but I'd set it to 10 just to make sure.

                    linear_extrude(height = ht, convexity=10) {
                        _honeycomb(shp, spacing = spacing, hex_wall = wall);

@rjcarlson49
Copy link
Author

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants