include <BOSL2/std.scad>;

// Constants

// Cooordinates
X=0;
Y=1;
Z=2;

// Offset
OFFSET=0.01; 


/**
 * Handle for bézier point
 * 
 * @param point     - Point to manage
 * @param angle     - Angle starting as 3h00
 * @param strength  - Handle distance from manage point  
 */
 
function handle(point,angle,strength) = [
    point[0] + polar_to_xy(strength,angle)[0]   ,
    point[1] + polar_to_xy(strength,angle)[1]   
    ]; 



/**
 * Show Debug point
 */
module debugPoint(point, id, color,textSize=20,r=1.5,t = [0,0,0]) {

    translation = is_undef(t) ? [0,0,0] : t;

    translate(point) {
        color(is_undef(color) ? "white" : color) sphere(r = r);
        
        //translate([3, 3, 0.6]) {

       
        translate([textSize/7+translation[0], textSize/7+translation[1], textSize/10+translation[2]]) {
            color("white") 
            scale([0.2, 0.2, 1]) 
            linear_extrude(height = 0.1) 
            text(str(id), size = textSize, halign = "center", valign = "center");
        }
    }
}

/**
 * Show vnf points
 */
module vnfPoints(points,textSize=1,r=0.1) {
    for(i = [0:1:len(points)-1]) 
        for(j = [0:1:len(points[i])-1]) {
            pos = points[i][j];
            label = str(i,",",j);
            debugPoint(pos, label, "Red", textSize=textSize, r=r);
        }
}


/**
 * Displays debug information for a path by visualizing its self-crossings.
 * 
 * @param path - The input path to analyze for self-crossings.
 * 
 * This module:
 * - Splits the path at points where it intersects itself.
 * - Renders each segment of the split path with different colors for easy identification.
 */
module showDebugPath( path ) {
    assert(is_path(path),"Path to show is not a path");
    assert(is_path_simple(path),"Path is not simple");
    rainbow(split_path_at_self_crossings(path)) 
        stroke($item, closed=false, width=0.2);
}


/**
 * Rounded Triangle
 */
module rounded_triangle(radius, height) {
    triangle_points = [[0, 0], [75, 0], [0, -35]]; // Equilateral triangle with side length 100
    rounded_shape = round_corners( triangle_points, r=radius );
    mirror([0,0,1]) linear_extrude(height = height) polygon(rounded_shape);
}


/**
 * Function to translate a path manually along X and Y
 * 
 * @param path  - Original path
 * @param dx    - x translation 
 * @param dy    - y translation 
 */ 
function translate_path(path, dx=0, dy=0) = [for (p = path) [p[0] + dx, p[1] + dy]];   

/**
 * Convert points to bezier curve
 *
 * @param points  - Points
 *
 * @return a path
 */
function asCurve( points,steps=128 ) = bezpath_curve(points,N=3,splinesteps=steps);


/**
 * Print path points
 */
module print_path_points(path) {
    for (i = [0:len(path)-1]) {
        echo(str("\t Point ", i, ": [", path[i][0], ", ", path[i][1], "]"));
    }
}

/**
 * Expand path 
 *
 * @param path  - Original path
 * @param delta - distance to expand
 *
 * Keep the same number of points
 */
function expandPath( path, delta ) = 
        offset(
            deduplicate(path),
            delta=delta,
            chamfer=false,
            same_length=true
       )
    ;


/**
 * Inches to centimeter conversion
 */ 
function inches_to_cm(inches) = inches * 2.54;



/**
 * Calculates heights for n layers where the first layer starts at 0 and the last at fin_thickness.
 * 
 * @param n - Number of layers.
 * @param fin_thickness - The total height to be divided.
 * @return An array where each element represents the height of the top of each layer.
 */
function layerHeights(n, fin_thickness) = 
    let(
        layer_height = fin_thickness / (n - 1)
    )
    [ for (i = [0 : n-1]) i * layer_height ];

/**
 * Make a skirt around a profile
 *
 * @param profile       - Path ot the mold
 * @param moldThickness - Thickness of the mold
 * @param angle         - Angle of the skirt starting from flat angle
 * @param moldDeep      - Mold deep. Normally height of the skirt should be 3 times the thickness of the model
 * @param side          - Bottom or top part of the mold
 *
 */ 
module skirt( profile, moldThickness = 4 , angle = 45 , moldDeep, side = "bottom", heightFactor = 3, clearance = 0.2 ) {
    height = heightFactor * moldDeep;
    echo ("height",height);
    deviation = opp_ang_to_adj (height,angle);
//    deviation = 3;
    
    if ( side == "bottom" ) {
        lowInt  = profile;
        lowExt  = expandPath( lowInt    , moldThickness  );
        highInt = expandPath( lowInt    , deviation  );
        highExt = expandPath( lowInt    , deviation + moldThickness  );
        difference(){
            skin([lowExt   , highExt   ], z=[0          , height        ] , slices=0);
            skin([lowInt   , highInt   ], z=[-OFFSET    , height+OFFSET ] , slices=0);
        }            
    } else if ( side == "top" ) {
        lowInt  = expandPath( profile   , -moldThickness  );
        lowExt  = expandPath( profile   , -clearance  );
        highInt = expandPath( profile    , +deviation-moldThickness  );
        highExt = expandPath( profile    , +deviation -clearance  );
        difference(){
            skin([lowExt   , highExt   ], z=[0          , height        ] , slices=0);
            skin([lowInt   , highInt   ], z=[-OFFSET    , height+OFFSET ] , slices=0);
        }            
        
    }
}    

if ( false ) {
    skirt(
        rect([30,30]),
        moldDeep=5,
        moldThickness = 3,
        side="bottom"
    );
    up(1)
    skirt(
        rect([30,30]),
        moldDeep=5,
        moldThickness = 3,
        side="top",
        clearance=1
        
    );
}