OpenJSCAD radial wire organizers
3D Icon

OpenJSCAD is a programmatic way of creating 3D objects with two advantages over my preferred method, Blender.

  • It’s easier to create measured objects, so it’s ideal for 3D printing parts that require precision for things like screw holes and attachments.
  • It has an API for taking in variables that can dynamically affect the final model. So users can create useful, custom models without needing to be able to code or be a modeler.
Quick JS canvas sketch A quick JS canvas sketch to test the radial pattern

My C-Clamp visualization – JSFiddle: https://jsfiddle.net/fv41wqu9/3/

For my first project using OpenJSCAD I wanted to create something that would organize all the wires in my house. I often use zip ties but my biggest issue with that method is that it’s time consuming and wasteful to temporarily remove one of the cords. My solution was to create a script that asks for an array of wire diameters and then computes a radial clip that holds the wires neatly away from each other. I like this project because I think it’s a great example of the power of both openJSCAD and 3d printers to create something that wouldn’t be possible to mass manufacture because of the different sizes and combinations of wires, necessary. It was also an interesting math problem, getting the clips holders to organize around a circle, point towards the center and move in or out depending on the size and number of the wire holders required the code to be very dynamic. Using an html5 canvas on JSfiddle to quickly plot things out was a big help. For instance, to get the C shaped clamp that holds wires, I need to plot points along the out edge in the right order. I ended up with a string of dots that allowed me to quickly visualize what I was coming up with.

To use it, just download the radial-wire-clip OpenJSCAD file and drop it into the “Drop your .jscad file here” box on the OpenJSCAD parser. After that, the ‘clip sizes’ field takes a list of floating point numbers, separated by commas. They should be the diameters of each wire it will hold, in millimeters.

Clip Gallery

Gallery Icon

OpenJSCAD code


function getParameterDefinitions() {
    return [
      { "name":"wire_diams_string", "caption":"Clips sizes (separated by commas)", "type":"text", "default":"2,4,5,6,8"},
      { "name":"clip_thickness", "caption":"Thickness of each clip", "type":"float", "default":"6"}
    ];
}

function main(params) {

    var wire_diams = params.wire_diams_string.split(",").map(parseFloat); //turn the csv's into an array of floats
    var numClips = wire_diams.length;
    var clipSteps = 2 * Math.PI / numClips; // amount to add to theta each time (degrees)
    var clipR = ((numClips * 1.5) + 2); //scale the root circle up linearly with the number of clips
    var allClips = new CSG(); //a blank object to start adding clips to

    var iter = 0; //This is for the main 'clip' loop, incremented once for each loop
    for (k = 0.1; k < = 2 * Math.PI; k += clipSteps) {

        //these set up the clip points that will be extruded
        var theta = 1.5; // angle that will be increased each loop
        var outertheta = 1.4; //s
        var step = 2 * Math.PI / 40; // amount to add to theta each time (degrees)
        var r = wire_diams[iter]/2;
        var outerR = r + 2;

        //////////ROOT RADIUS VARS (Where the clips are placed)
        //Make the root radius variably bigger or smaller if the clip size is bigger or smaller
        //how much to push out each clip as it gets bigger (2 is the smallest size)
        xoffset = yoffset = r/2*1.4; 
        //Final x and y for placing each Clip
        var rootX = (clipR + xoffset) * Math.cos(k);
        var rootY = (clipR + yoffset) * Math.sin(k);

        //Loop for points inside of clip shape
        var points = [];
        for (i = theta; i <= 2 * Math.PI; i += step) { x = r * Math.cos(i); y = r * Math.sin(i); points.push([x, y]); } //loop for outside points of clip shape, noticed it's reversed! This is because the points on the outside should start right next to the last inside loop point. for (i = 2 * Math.PI; i >= outertheta; i -= step) {
            x = outerR * Math.cos(i);
            y = outerR * Math.sin(i);
            points.push([x, y]);
        }
        var shape = CAG.fromPoints(points);
        var extruded = shape.extrude({
            offset: [0, 0, params.clip_thickness], // direction for extrusion
        });

        //Figure out the angle for each clip to point towards then center, then move the clip to the outside radius
        var angle = Math.atan2(0 - rootY, 0 - rootX);
        angle = angle * (180 / Math.PI);
        extruded = extruded.rotateZ(angle + 145);
        extruded = extruded.translate([rootX, rootY, 0]);

        allClips = allClips.union(extruded);

        iter++;
    }

    // The inside cylinder that connects the clips:
    var cylinder = CSG.cylinder({
        start: [0, 0, 0],
        end: [0, 0, 4],
        radius: clipR - 1.15,
        resolution: 30 // optional
    });
    //cylinder = cylinder.rotateZ(4);

    finalform = allClips.union(cylinder);

    return finalform;
}

References