Skip to content

Latest commit

 

History

History

extra

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

extra.scad

Overview

This library contains a collection of reusable modules and functions that can be used in various OpenSCAD projects. The modules are designed to perform common tasks, such as creating geometric shapes, transformations, and other useful operations. Each module is self-contained and can be easily integrated into other OpenSCAD scripts. Additionally, the library includes a section for experimental functions and techniques, which are used for testing new ideas and exploring different approaches in OpenSCAD scripting.

2D

Circle sector

Create a circle sector given an angle from 0° ecluded to 360° included angle ∈ ] 0; 360 ]:

circle_sector(radius, start_angle, end_angle);

Parameters:

  • radius: sector circle radius expressed in mm
  • start_angle: sector start angle expressed in degrees
  • end_angle: sector end angle expressed in degrees

Note that the end_angle has to be greater than the start_angle.

use <extra.scad>

minor_angle = 60;
straight_angle = 180;
major_angle = 240;
radius = 160;
start_angle = 45;
thickness = 3;

// Create a minor sector
linear_extrude(thickness) translate([-400, -150, 0]) {
    circle_sector(2*radius, start_angle, start_angle + minor_angle);
}

// Create a semicircula sector
linear_extrude(thickness) translate([0, 0, 0]) {
    circle_sector(radius, start_angle, start_angle + straight_angle);
}

// Create a major sector
linear_extrude(thickness) translate([300, 0, 0]) {
    circle_sector(radius, start_angle, start_angle + major_angle);
}

./images/fig_circle_sector_demo.png

Isosceles trapezium

Create an isosceles trapezium with optional centering:

isosceles_trapezium(base, top, height, center);

Parameters:

  • base or b: Length of the bottom of the base (default 0).
  • top or b2: Length of the top of the trapezium (default 0).
  • height or h: Height of the trapezium (default 0).
  • center: Boolean to center the trapezium on the axes (default false).
use <extra.scad>

linear_extrude(0.5) {
    isosceles_trapezium(base=36, top=26, height=24, center=true);
}

./images/fig_isosceles_trapezium_demo.png

Isoscele trapezium

Create a rectangle trapezium with optional centering

rectangle_trapezium(base, top, height, center);

Parameters:

  • base or b: Length of the bottom of the base (default 0).
  • top or b2: Length of the top of the trapezium (default 0).
  • height or h: Height of the trapezium (default 0).
  • center: Boolean to center the trapezium on the axes (default false).
use <extra.scad>

linear_extrude(0.5) {
    rectangle_trapezium(base=26, top=36, height=24, center=true);
}

./images/fig_rectangle_trapezium_demo.png

Ellipse

Create an ellipse

ellipse(length, width)

Parameters:

  • length or l: The major axis diameter of the ellipse.
  • width or w: The minor axis diameter of the ellipse.

The module accepts either short (l, w) or long (length, width) parameter names. If both are provided, the long names take precedence.

Examples:

use <extra.scad>

ellipse(length = 10, width = 5);
translate([-6, -6, 0]) ellipse(l = 8, w = 4);

./images/fig_eclipse_demo.png

Fillet

Applies fillets on reflex corners to a 2D shape without altering its overall size.

fillet_reflex_angles(radius) children_2d_object();

Parameters:

  • radius: The fillet radius, must be greater than 0.
use <extra.scad>

module 2d_object() {
    union() {
        circle(50);
        square([50, 100]);
    }
}

fillet_reflex_angles(10) 2d_object();

./images/fig_fillet_on_2d_shape_demo.png

Thickness

Transforms a 2D shape into a hollow object by adding a wall of the specified width. A positive width creates an outward contour, while a negative width generates an inward contour.

thickness(width) children_2d_object();

Parameters:

  • width: The width or thickness of the wall to be generated around the 2d shape.
use <extra.scad>

module 2d_object() {
    union() {
        circle(50);
        square([50, 100]);
    }
}

// Inward thickness
translate([-60, 0, 0]) thickness(-10) 2d_object();

// Outward thickness
translate([60, 0, 0]) thickness(10) 2d_object();

./images/fig_thickness_demo.png

Sinusoidal Circle

Generate a sinusoidal circle.

sinusoidal_circle(radius, amplitude, frequency, segments);

Parameters:

  • radius: The base radius of the circle, determining its average size.
  • amplitude: The height of the sinusoidal waves, controlling how much the circle’s radius fluctuates.
  • frequency: The number of sinusoidal waves or oscillations around the circle. A higher frequency means more waves in the same circle.
  • segments: The number of segments used to approximate the circle. A higher value results in a smoother curve.
use <extra.scad>

sinusoidal_circle( 30,      // base radius
                   3,       // wave amplitude
                   10,      // wave frequency
                   1000 );  // number of segments

./images/fig_sinusoidal_circle_demo.png

3D

Cylinder Sector

Create a cylinder sector given an angle from 0° ecluded to 360° included angle ∈ ] 0; 360 ]:

cylinder_sector(radius, height, start_angle, end_angle);

Parameters:

  • radius: cylinder radius expressed in mm
  • height: Cylinder height expressed in mm
  • start_angle: sector start angle expressed in degrees
  • end_angle: sector end angle expressed in degrees
use <extra.scad>

cylinder_sector(100, 10, 0, 290);

./images/fig_cylinder_sector_demo.png

Transformations

Symmetry plane

Mirrors the child object along a plane defined by the Cartesian axis (XY, XZ, or YZ) while retaining the original object.

symmetry_plane(plane) children_object();

Parameters:

  • XY, xy, YX or yx: the plane XY
  • XZ, xz, ZX or zx: the plane XZ
  • YZ, yz, ZY or zy: the plane YZ
use <extra.scad>

module xy_object() {
  r = 10;
  translate([0, 40, r]) {
    sphere(r = 10);
  }
}

symmetry_plane("XZ") xy_object();
symmetry_plane("YZ") translate([15, 0, 0]) cube(size = [10, 20, 10]);

./images/fig_symmetry_plane_demo.png

XOR patterns

Parametric 3D Model Based on Binary Input

use <extra.scad>;

// Parametric settings
size = 10; // Grid size
cell_size = 5; // Size of each cell
binary_input = [1, 0, 1, 0, 1, 1, 0, 1, 0, 1]; // Example binary input

// Function to visualize a cell based on its XOR state
function cell_state(i, j) = xor(binary_input[i % len(binary_input)], binary_input[j % len(binary_input)]); // Alternating pattern based on binary input

// Create a grid based on the binary input
for (i = [0 : size-1]) {
    for (j = [0 : size-1]) {
        // Calculate cell position based on row and column
        x_pos = i * cell_size;
        y_pos = j * cell_size;

        // Use the XOR result to decide if the cell is visible
        if (cell_state(i, j)) {
            translate([x_pos, y_pos, 0])
                cube([cell_size, cell_size, 1]);  // Create a visible cell
        }
    }
}

./images/fig_3d_model_based_on_binary_input_demo.png

Dynamic Rectilinear Grid with Interference

use <extra.scad>;

// Parametric settings
size = 20; // Grid size
cell_size = 5; // Size of each cell
wave_speed = 2; // Wave speed (how fast the wave moves)
time = 10; // Simulation time to show propagation over multiple steps

// Function to simulate wave interference using XOR
function wave_interference(i, j, time) = 
    xor(floor((i + time * sin(i / 3.0)) / wave_speed) % 2, floor((j + time * cos(j / 3.0)) / wave_speed) % 2);  // Wave with interference

// Create a grid based on the wave interference pattern
for (i = [0 : size-1]) {
    for (j = [0 : size-1]) {
        // Calculate cell position based on row and column
        x_pos = i * cell_size;
        y_pos = j * cell_size;
        wave = wave_interference(i, j, time);  // Get wave interference pattern

        // Create a visible cell based on the wave
        if (wave) {
            color("cyan")
                translate([x_pos, y_pos, 0])
                    cube([cell_size, cell_size, 1]);  // Visible wave crest
        } else {
            color("magenta")
                translate([x_pos, y_pos, 0])
                    cube([cell_size, cell_size, 1]);  // Visible wave trough
        }
    }
}

./images/fig_rectilinear_grid_with_interference_demo.png

XOR lattice structure

use <extra.scad>;

grid_size = 6; // Lattice size
spacing = 8;   // Spacing between lattice points

// Function to create lattice points using XOR logic
function lattice(x, y, z) = xor(x % 2, y % 2) && xor(y % 2, z % 2);  // XOR logic for 3D lattice

// Direct assert check for valid integer input
assert(grid_size >= 0 && floor(grid_size) == grid_size, "Invalid grid_size value");
assert(spacing >= 0 && floor(spacing) == spacing, "Invalid spacing value");

// Generate the lattice structure
for (x = [0 : grid_size-1]) {
    for (y = [0 : grid_size-1]) {
        for (z = [0 : grid_size-1]) {
            if (lattice(x, y, z)) {
                translate([x * spacing, y * spacing, z * spacing])
                    sphere(1);  // Lattice point visible by XOR rule
            }
        }
    }
 }

./images/fig_xor_lattice_structure_demo.png

Cartesian coordinate system representation

Draw line

Draw a line segment given two points, with an optional parameter to extend the line beyond these points.

draw_line(point1,
          point2,
          thickness = line_thickness,
          extend = false,
          factor = multiplication_factor);

Parameters:

  • point1: the first point of the line [x0, y0, z0]
  • point2: the second point of the line [x1, y1, z1]
  • thickness: the thickness of the line
  • extend: optional parameter to extend the line beyond the given points
  • factor: optional parameter that is the multiplication factor for the line extention
use <extra.scad>

// Instantiating two points defining a line 
p1 = [-4, 2, 3];
p2 = [-8, 20, 30];

// Draw the line
color("Red") draw_line(p1, p2);
// Draw an extented line parallel to the initial line 
color("Green") translate([10, 0, 0]) {
  draw_line(p1, p2, extend = true, factor = 0.2);
}

./images/fig_line_demo.png

Draw vector

Draw a vector with its direction arrow.

draw_vector(point1, point2, thickness);

Parameters:

  • point1: the first point of the line [x0, y0, z0]
  • point2: the second point of the line [x1, y1, z1]
  • thickness: the thickness of the line
use <extra.scad>

// Lines thickness
lt1 = 0.8;
lt2 = 0.4;

// Instantiating two points defining the vector tail and vector tip fir the vector u
u1 = [1, 2, 3];
u2 = [10, 20, 30];

// Instantiating two points defining the vector tail and vector tip fir the vector v
v1 = [-2, 7, 8];
v2 = [-12, 10, 31];

// Draw the vectors
color("Magenta", 1.0) draw_vector(u1, u2, lt1);
color("Tomato", 1.0) draw_vector(v1, v2, lt2);

./images/fig_vector_demo.png

Draw parallelepiped

Draw parallelepiped built by two vectors.

draw_parallelepiped(point1, point2, thickness)

Parameters:

  • point1, point2: two vectors represented by the three dimensional points
  • thickness: the thickness of the parallelepiped
use <extra.scad>

// Instantiating two points defining the vector tail and vector tip
u = [19, 3, 2];
v = [-4, 20, 4];

// Draw the parallelepiped
draw_parallelepiped(u, v, thickness = 0.1);

// Draw the vectors
color("Red") draw_vector([0, 0, 0], u, 0.4);
color("Blue") draw_vector([0, 0, 0], v, 0.4);

./images/fig_draw_parallelepiped_demo.png

use <extra.scad>

// Origin
o = [0, 0, 0];

// Define the two vectors
v1 = [15, 0, 0];
v2 = [-10, 1.2, 0];

// Angle of rotation around the z-axis
angle = $t * 360;

// Calculate the rotated v1 manually
v1_rotated = [v1[0] * cos(angle) - v1[1] * sin(angle),
              v1[0] * sin(angle) + v1[1] * cos(angle),
              v1[2]];

// Compute the cross product
v1_x_v2 = cross(v1_rotated, v2);

// Visualization of the vectors
color("Green") draw_vector(o, v1_rotated);
color("Red") draw_vector(o, v2);
color("Blue") draw_vector(o, v1_x_v2);
draw_parallelepiped(v1_rotated, v2);

./images/fig_parallelepiped_cross_animation.gif

Draw vector components

Draw a vector with its direction arrow and vector components.

draw_vector_components(point1, point2, line_thickness, bounding_box)

Parameters:

  • point1: the first point of the line [x0, y0, z0]
  • point2: the second point of the line [x1, y1, z1]
  • thickness: the thickness of the line
  • bounding_box: optional parameter to draw the vectors boundary box
use <extra.scad>

// Line thickness
lt = 0.4;

// Instantiating two points defining a vector in the cartesian system
p1 = [1, 2, 3];
p2 = [10, 20, 30];

// Draw the vector
draw_vector(p1, p2, lt);
// Draw the vector components
draw_vector_components(p1, p2, lt, boundary_box = true);

./images/fig_vector_components_demo.png

Functions

Degrees to radians

Function to convert degrees to radians.

deg_to_rad(deg);

Parameters:

  • deg: the angle in degrees
use <extra.scad>

angle_deg = 45;
angle_rad = deg_to_rad(angle_deg);

echo("Angle in degrees:", angle_deg);
echo("Angle in radians:", angle_rad);

./demo/converting_degrees_to_radians.echo

cat ./demo/converting_degrees_to_radians.echo
ECHO: "Angle in degrees:", 45
ECHO: "Angle in radians:", 0.785398

Radians to degrees

Function to convert radians to degrees.

rad_to_deg(rad);

Parameters:

  • rad: the angle in radians
use <extra.scad>

angle_rad = 0.785398;
angle_deg = rad_to_deg(angle_rad);

echo("Angle in radians:", angle_rad);
echo("Angle in degrees:", angle_deg);

./demo/converting_radians_to_degrees.echo

cat ./demo/converting_radians_to_degrees.echo
ECHO: "Angle in radians:", 0.785398
ECHO: "Angle in degrees:", 45

Pad to three

Function that transforms a one- or two-dimensional vector into a three-dimensional vector.

pad_to_three(point);

Parameters:

  • point: Either a one-, two- or three-dimensional vector.
use <extra.scad>

// One-dimensional vector
vec_1_dim = [11];
// Two-dimensional vector
vec_2_dim = [15, 10];
// Three-dimensional vector
vec_3_dim = [20, -15, -10];
// Four-dimensional vector
vec_4_dim = [-5, 9, 10, 12];

vectors = [vec_1_dim, vec_2_dim, vec_3_dim, vec_4_dim]; 

for (vector = vectors) {
  echo(vector, pad_to_three(vector));
}

./demo/one_or_two_dimensional_vectors_into_a_three_dimensional_vectors.echo

cat ./demo/one_or_two_dimensional_vectors_into_a_three_dimensional_vectors.echo
ECHO: [11], [11, 0, 0]
ECHO: [15, 10], [15, 10, 0]
ECHO: [20, -15, -10], [20, -15, -10]
ECHO: [-5, 9, 10, 12], undef

Unit vector

The unit vector (also called normalized vector) is the vector of size one that goes in the same direction as the original vector.

unit_vector(v);

Parameters:

  • point: Either a one-, two- or three-dimensional vector.
use <extra.scad>

v = [30, 60, 90];
unit_v = unit_vector(v);

echo("vector", v);
echo("unit vector", unit_v);

./demo/calculate_the_unit_vector.echo

cat ./demo/calculate_the_unit_vector.echo
ECHO: "vector", [30, 60, 90]
ECHO: "unit vector", [0.267261, 0.534522, 0.801784]

Vector addition

Function to add vectors

vector_addition(v1, v22);

Parameters:

  • v1, v2: are either one-, two- or three-dimensional vectors
use <extra.scad>

v1 = [3, 16, 15];
v2 = [23, 26, 10];

v = vector_addition(v1, v2);

echo("Displacement vector", v);

./demo/calculate_the_vector_addition.echo

cat ./demo/calculate_the_vector_addition.echo
ECHO: "Displacement vector", [26, 42, 25]
use <extra.scad>

// Defining the tip of two vectors
v1 = [3, 16, 15];
v2 = [23, 26, 10];

// Compute the vector addition to the two vectors and and store its value in variable v
v = vector_addition(v1, v2);

// Setting the reference for the two vectors
origin = [0, 0, 0];

// Drawing vector v1 from the origin
color("Red", 1.0) draw_vector(origin, v1);
// Drawing vector v2 from the tip of vector v1
translate(v1) color("Green", 1.0) draw_vector(origin, v2);
// Drawing the computed vector v from the origin. The tip of v lands on the tip of v2  
color("Yellow", 1.0) draw_vector(origin, v);

./images/fig_calculate_the_vector_addition.png

use <extra.scad>

// Defining the tip of two vectors
v1 = [3, 16, 15];
v2 = [23, 26, 10];

// Compute the negative of v2
nv2 = (-1)*v2;

// Compute v1+(-v2) -> v1-v2 and store the value in variable v
v = vector_addition(v1, nv2);

// Setting the reference for the two vectors
origin = [0, 0, 0];

// Draw vector v1 fom the origin
color("Red", 1.0) draw_vector(origin, v1);
// Draw vector v2 from the tip of v1
translate(v1) {
  color("Green", 1.0) draw_vector(origin, nv2);
}
// Dra the computed vector v from the origin. The tip of v lands on the tip of v2  
color("Yellow", 1.0) draw_vector(origin, v);

./images/fig_vector_substraction_example.png

Dot product

The dot product (or scalar product)

dot(v1, v2)

Parameters:

  • v1, v2: are either one-, two- or three-dimensional vectors
use <extra.scad>

// Test dot product (vector tip points)
u = [-4, 20, 4];
v = [9, 3, 2];

// Drawing parameters
thickness = 0.3;
origo = [0, 0, 0]; // ISSUE: other origo values than the origin at [0, 0, 0] don't work

// Draw two vectors, u and v with the same origo 
color("Red") draw_vector(origo, u, thickness);
color("Blue") draw_vector(origo, v, thickness);

// Compute the projection of u onto v
//projection_u_on_v = projection_point_on_vector(v, u);
projection_u_on_v =
  projection_point_on_vector(origo, v, [origo[0] + u[0],
                                            origo[1] + u[1],
                                            origo[2] + u[2]]);

// Draw the projection of u onto v
color("Gray") draw_line(u, projection_u_on_v, thickness/3);

// Draw the projection vector of u onto v
color("Green") draw_vector(origo, projection_u_on_v, thickness);

// Compute the dot product of u, v
dot_product = dot(u, v);

// Normalize vector v to get the unit vector
unit_v = unit_vector(v);

// Place the point along vector v at the dot product value
dot_product_point_on_v = [for (i = [0:2]) unit_v[i] * dot_product];

// Draw the point using draw_point module
color("SkyBlue") draw_point(dot_product_point_on_v, cross = false);

// Draw the line from the tip of vector v to the the dot product value
color("SkyBlue", 0.67) draw_line(v, dot_product_point_on_v, thickness);

./images/fig_calculate_the_dot_product.png

use <extra.scad>

// Test dot product (vector tip points) at custom reference point
u = [-17, 15, -1];
v = [5, 3, 2];

// Drawing parameters
thickness = 0.3;
reference = [-5, -10, 8]; // ISSUE: other reference values than the origin at [0, 0, 0] don't work

// Draw two vectors, u and v with the same reference 
color("Red") draw_vector(reference,
                         [reference[0] + u[0],
                          reference[1] + u[1],
                          reference[2] + u[2]],
                         thickness);
color("Blue") draw_vector(reference,
                          [reference[0] + v[0],
                           reference[1] + v[1],
                           reference[2] + v[2]],
                          thickness);

// Compute the projection of u onto v
projection_u_on_v =
  projection_point_on_vector(reference, v, [reference[0] + u[0],
                                            reference[1] + u[1],
                                            reference[2] + u[2]]);

// Draw the projection of u onto v
color("Gray") draw_line([reference[0] + u[0],
                         reference[1] + u[1],
                         reference[2] + u[2]],
                        projection_u_on_v,
                        thickness / 3);

// Draw the projection vector of u onto v
color("Green") draw_vector(reference, projection_u_on_v, thickness);

// Compute the dot product of u, v
dot_product = dot(u, v);

// Normalize vector v to get the unit vector
unit_v = unit_vector(v);

// Place the point along vector v at the dot product value
dot_product_point_on_v = [for (i = [0:2]) reference[i] + unit_v[i] * dot_product];

// Draw the point using draw_point module
color("SkyBlue") draw_point(dot_product_point_on_v, cross = false);

// Draw the line from the tip of vector v to the dot product value
color("SkyBlue", 0.67) draw_line([reference[0] + v[0],
                                 reference[1] + v[1],
                                 reference[2] + v[2]],
                                dot_product_point_on_v,
                                thickness);

./images/fig_calculate_the_dot_product_with_reference_other_than_origo.png

The slope function

Calculate the slope between two points

slope(p1, p2);

Parameters:

  • p1, p2: are two vector points up to three dimensions
use <extra.scad>

// Define points
point1 = [2, 3];
point2 = [15, 21];

// Calculate rise and run
rise = point2[1] - point1[1];
run = point2[0] - point1[0];

// Draw points
draw_point(point1);
draw_point(point2);

// Draw line between points
color("red") draw_line(point1, point2);

// Draw rise and run
color("green")
draw_line(point1, [point2[0], point1[1]]); // Run
draw_line([point2[0], point1[1]], point2); // Rise

// Annotate points
translate([point1[0] - 2.5, point1[1], 0.3])
text(str("(", point1[0], ", ", point1[1], ")"), size = 1, valign = "center", halign = "center");

translate([point2[0] - 3.5, point2[1], 0.3])
text(str("(", point2[0], ", ", point2[1], ")"), size = 1, valign = "center", halign = "center");

// Annotate rise and run
translate([(point1[0] + point2[0]) / 2, point1[1] - 2.0, 0.3])
text("Run", size = 1, valign = "center", halign = "center");

translate([point2[0] + 2.5, (point1[1] + point2[1]) / 2, 0.3])
text("Rise", size = 1, valign = "center", halign = "center");

// Annotate slope
translate([(point1[0] + point2[0]) / 2 - 6, (point1[1] + point2[1]) / 2, 0.3])
text(str("Slope = ", slope(point1, point2)), size = 1, valign = "center", halign = "center");

./images/fig_slope_demo.png

use <extra.scad>

point1 = [2, 3];
point2 = [15, 21];

slope = slope(point1, point2);
perpendicular_slope = perpendicular_slope(slope);

echo("slope", slope);
echo("perpendicular slope", perpendicular_slope);

./demo/slope_and_perpendicular_slope.echo

cat ./demo/slope_and_perpendicular_slope.echo
ECHO: "slope", 1.38462
ECHO: "perpendicular slope", -0.722222

Lines intersection

Function to find the intersection point of two lines

lines_intersection(line1, line2)

Parameters:

  • line1, line2: a line is determined by two points of two dimensions encapsulated in a list
use <extra.scad>

// Instanstiating four points defining two lines 
u0 = [8, 12];
u1 = [-4, 2];
v0 = [19, 0];
v1 = [-7, 4];

// Drawing the lines
color("Red")draw_line(u0, u1, extend = true);
color("Green")draw_line(v0, v1, extend = true);

// Compute the intersection point of the two lines and stor the value
i = lines_intersection([u0, u1], [v0, v1]);

// Draw the intersection point
color("Magenta") draw_point(i, cross = false, factor = 8);

./images/fig_lines_intersection_demo.png

XOR and reduce XOR functions

xor(bol_a, bol_b)

Parameters:

bool_a: A boolean value true (1) or false (0). bool_b: A boolean value true (1) or false (0).

use<extra.scad>

function test_xor() = [
    [true, true, xor(true, true)],    // Expected false
    [true, false, xor(true, false)],  // Expected true
    [false, true, xor(false, true)],  // Expected true
    [true, true, xor(true, true)],    // Expected false
];

// Print results
for (t = test_xor()) 
    echo("A: ", t[0], " B: ", t[1], " XOR: ", t[2]);

./demo/test_xor.echo

cat ./demo/test_xor.echo
ECHO: "A: ", true, " B: ", true, " XOR: ", false
ECHO: "A: ", true, " B: ", false, " XOR: ", true
ECHO: "A: ", false, " B: ", true, " XOR: ", true
ECHO: "A: ", true, " B: ", true, " XOR: ", false
use <extra.scad>

// Example test for reduce_xor
function test_reduce_xor() = [
    [ [true, true], false ],          // true XOR true = false
    [ [true, false], true ],          // true XOR false = true
    [ [false, true], true ],          // false XOR true = true
    [ [false, false], false ],        // false XOR false = false
    [ [true, false, true], false ],   // (true XOR false) XOR true = false
    [ [true, false, false], true ],   // (true XOR false) XOR false = true
];

for (test = test_reduce_xor()) {
    result = reduce_xor(test[0]);
    echo("Input: ", test[0], " Expected: ", test[1], " Got: ", result);
    assert(result == test[1], "Test failed!");
 }

./demo/test_reduce_xor.echo

cat ./demo/test_reduce_xor.echo
ECHO: "Input: ", [true, true], " Expected: ", false, " Got: ", false
ECHO: "Input: ", [true, false], " Expected: ", true, " Got: ", true
ECHO: "Input: ", [false, true], " Expected: ", true, " Got: ", true
ECHO: "Input: ", [false, false], " Expected: ", false, " Got: ", false
ECHO: "Input: ", [true, false, true], " Expected: ", false, " Got: ", false
ECHO: "Input: ", [true, false, false], " Expected: ", true, " Got: ", true

Conversion functions

Integer to binary conversion

use <extra.scad>;

// Test cases for integer to binary conversion
function test_integer_to_binary() = [
    // Intger value, asserted binary value
    [5, "101"],
    [10, "1010"],
    [0, "0"],
    [15, "1111"],
    [8, "1000"]
];

// Execute tests
for (test = test_integer_to_binary()) {
    result = integer_to_binary(test[0]);
    echo("Input: ", test[0], " Expected: ", test[1], " Got: ", result);
    assert(result == test[1], "Test failed!");
 }

./demo/test_integer_to_binary.echo

cat ./demo/test_integer_to_binary.echo
ECHO: "Input: ", 5, " Expected: ", "101", " Got: ", "101"
ECHO: "Input: ", 10, " Expected: ", "1010", " Got: ", "1010"
ECHO: "Input: ", 0, " Expected: ", "0", " Got: ", "0"
ECHO: "Input: ", 15, " Expected: ", "1111", " Got: ", "1111"
ECHO: "Input: ", 8, " Expected: ", "1000", " Got: ", "1000"

Binary to integer conversion

use <extra.scad>;

// Test cases for binary to decimal conversion
function test_binary_to_integer() = [
    // Binary value, asserted integer value
    ["101", 5],
    ["1010", 10],
    ["0", 0],
    ["1111", 15],
    ["1000", 8]
];

// Execute tests
for (test = test_binary_to_integer()) {
    result = binary_to_integer(test[0]);
    echo("Input: ", test[0], " Expected: ", test[1], " Got: ", result);
    assert(result == test[1], "Test failed!");
 }

./demo/test_binary_to_integer.echo

cat ./demo/test_binary_to_integer.echo
ECHO: "Input: ", "101", " Expected: ", 5, " Got: ", 5
ECHO: "Input: ", "1010", " Expected: ", 10, " Got: ", 10
ECHO: "Input: ", "0", " Expected: ", 0, " Got: ", 0
ECHO: "Input: ", "1111", " Expected: ", 15, " Got: ", 15
ECHO: "Input: ", "1000", " Expected: ", 8, " Got: ", 8

String to number comversion

use <extra.scad>;

// Example test cases for the to_number function
test_cases = [
    "12345",     // Positive number
    "-98765",    // Negative number
    "0",         // Zero
    "000123",    // Leading zeros
    "-001234",   // Negative with leading zeros
    "987654321"  // Large number
];

// Test the to_number function with each case
for (tc = test_cases) {
    result = to_number(tc);
    echo(str("Input: ", tc, " Result: ", result));  // Output the input and result
 }

./demo/test_to_number.echo

cat ./demo/test_to_number.echo
ECHO: "Input: 12345 Result: 12345"
ECHO: "Input: -98765 Result: -98765"
ECHO: "Input: 0 Result: 0"
ECHO: "Input: 000123 Result: 123"
ECHO: "Input: -001234 Result: -1234"
ECHO: "Input: 987654321 Result: 9.87654e+8"