Simple S-Hook

From BITPlan Wiki
Jump to navigation Jump to search

Simple S-Hook Design

The preview below currently only works for older JSCad code using the CSG syntax. See OpenJsCad Issue 448 <jscad>// title : S Hook // author : Joost Nieuwenhuijse // license : MIT License // description: a simple S-hook design // file : s-hook.jscad

// Here we define the user editable parameters: function getParameterDefinitions() {

 return [
   { name: 'topdiameter', caption: 'Inner diameter of top hook:', type: 'float', initial: 16.7 },
   { name: 'clampfactor', caption: 'Snugness of top hook (0 - 100):', type: 'float', initial: 25 },
   { name: 'cliplength', caption: 'Top hook clip length:', type: 'float', initial: 5 },
   { name: 'bottomdiameter', caption: 'Inner diameter of bottom hook:', type: 'float', initial: 20 },
   { name: 'height', caption: 'Outer height of the hook:', type: 'float', initial: 60 },
   { name: 'thickness', caption: 'Thickness:', type: 'float', initial: 5 },
   { name: 'width', caption: 'Width:', type: 'float', initial: 7 },
   {
     name: 'rounded', 
     type: 'choice',
     caption: 'Rounded edges',
     values: [0, 1],
     captions: ["No", "Yes (rendering will take a long time!)"], 
     initial: 0
   },    
   { name: 'roundness', caption: 'Diameter of rounded edges (if enabled):', type: 'float', initial: 1.5 },
   { name: 'buildwidth', caption: 'Width (x) of build area (to print multiple copies):', type: 'float', initial: 90 },
   { name: 'builddepth', caption: 'Depth (y) of build area (to print multiple copies):', type: 'float', initial: 90 }    
 ];

}

function main(params) {

 if(OpenJsCad.log) OpenJsCad.log("start");
 
 var pathresolution = 16;
 var expandresolution = 6;
 
 // construct the 2D path:
 var topradius = params.topdiameter/2;
 var bottomradius = params.bottomdiameter/2;
 var halfthickness = params.thickness/2;
 topradius += halfthickness;
 bottomradius += halfthickness;
 
 var roundness = params.roundness;
 if(params.rounded != 1)
 {
   roundness = 0;
 }
 roundness = Math.min(roundness, halfthickness-0.1, params.width/2-0.1);
 if(roundness < 0) roundness = 0;
 
 var clampfactor = params.clampfactor / 100;
 if(clampfactor < 0) clampfactor = 0;
 if(clampfactor >= 1) clampfactor = 1;
 clampfactor *= (topradius-halfthickness)/topradius;  
 
 var topstartangle = - 180 * Math.acos(1 - 2*clampfactor) / Math.PI;
 var tophookcenter = new CSG.Vector2D(topradius, 0);
 var tophookstart = tophookcenter.plus(CSG.Vector2D.fromAngleDegrees(topstartangle).times(topradius));
 var circledistance = params.height - topradius - bottomradius - 2 * params.thickness;
 if(circledistance < 0) circledistance = 0;
 var bottomhookcenter = new CSG.Vector2D(-bottomradius, -circledistance);
 var gravityangle = 90 - tophookcenter.minus(bottomhookcenter).angleDegrees();
 
 var path = new CSG.Path2D();
 // top hook curve:
 if(params.cliplength > 0)
 {
   var clipstart = new CSG.Vector2D([0, -1]).times(params.cliplength).plus(tophookstart);
   path = path.appendPoint(clipstart);
 }
 var topcurvepath = CSG.Path2D.arc({
   center: tophookcenter,
   radius: topradius,
   startangle: topstartangle,
   endangle: 180,
   resolution: pathresolution,
   maketangent: true
 });
 path = path.concat(topcurvepath);
 // straight middle part:
 if(circledistance > 0)
 {
   path = path.appendPoint([0, -circledistance]);
 }
 
 // bottom hook curve:
 var bottomcurvepath = CSG.Path2D.arc({
   center: bottomhookcenter,
   radius: bottomradius,
   startangle: 0,
   endangle: -180-gravityangle,
   resolution: pathresolution,
   maketangent: true
 });
 path = path.concat(bottomcurvepath);
 
 // center around origin, and rotate as it would hang under gravity:
 var centerpoint = tophookcenter.plus(bottomhookcenter).times(0.5);  
 var matrix = CSG.Matrix4x4.translation(centerpoint.negated().toVector3D(0));
 matrix = matrix.multiply(CSG.Matrix4x4.rotationZ(gravityangle));
 path = path.transform(matrix);
 // extrude the path to create a 3D solid
 var hook = path.rectangularExtrude(2*(halfthickness-roundness), params.width-2*roundness, pathresolution, true);
 hook = hook.translate([0, 0, -params.width/2+roundness]);
 
 // expand to create rounded corners:
 if(roundness > 0)
 {
   hook = hook.expand(roundness, expandresolution);
 }
 // hook = hook.toPointCloud(0.1);
 
 // determine how many objects will fit in the build area:
 var bounds = hook.getBounds();
 var objsize = bounds[1].minus(bounds[0]);
 var margin = 5; // distance between the copies
 var numx = Math.floor((params.buildwidth + margin) / (objsize.x + margin));  
 var numy = Math.floor((params.builddepth + margin) / (objsize.y + margin));
 if(numx < 1) numx = 1;  
 if(numy < 1) numy = 1;
 // and make the copies:
 var result = new CSG();
 for(var x = 0; x < numx; x++)
 {
   var deltax = ((1-numx)/2+x) * (objsize.x + margin); 
   var colresult = new CSG();
   for(var y = 0; y < numy; y++)
   {
     var deltay = ((1-numy)/2+y) * (objsize.y + margin);
     var translated = hook.translate(new CSG.Vector3D(deltax, deltay, 0));
     colresult = colresult.union(translated); 
   }
   result = result.union(colresult);
 }    
  
 if(OpenJsCad.log) OpenJsCad.log("finish");
 return result;

}</jscad>

Source code

Just cut&paste the source code below to https://www.openjscad.org/

// title      : S Hook
// author     : Joost Nieuwenhuijse
// license    : MIT License
// description: a simple S-hook design
// file       : s-hook.jscad

// Here we define the user editable parameters: 
function getParameterDefinitions() {
  return [
    { name: 'topdiameter', caption: 'Inner diameter of top hook:', type: 'float', initial: 16.7 },
    { name: 'clampfactor', caption: 'Snugness of top hook (0 - 100):', type: 'float', initial: 25 },
    { name: 'cliplength', caption: 'Top hook clip length:', type: 'float', initial: 5 },
    { name: 'bottomdiameter', caption: 'Inner diameter of bottom hook:', type: 'float', initial: 20 },
    { name: 'height', caption: 'Outer height of the hook:', type: 'float', initial: 60 },
    { name: 'thickness', caption: 'Thickness:', type: 'float', initial: 5 },
    { name: 'width', caption: 'Width:', type: 'float', initial: 7 },
    {
      name: 'rounded', 
      type: 'choice',
      caption: 'Rounded edges',
      values: [0, 1],
      captions: ["No", "Yes (rendering will take a long time!)"], 
      initial: 0
    },    
    { name: 'roundness', caption: 'Diameter of rounded edges (if enabled):', type: 'float', initial: 1.5 },
    { name: 'buildwidth', caption: 'Width (x) of build area (to print multiple copies):', type: 'float', initial: 90 },
    { name: 'builddepth', caption: 'Depth (y) of build area (to print multiple copies):', type: 'float', initial: 90 }    
  ];
}

function main(params) {
  if(OpenJsCad.log) OpenJsCad.log("start");
  
  var pathresolution = 16;
  var expandresolution = 6;
  
  // construct the 2D path:
  var topradius = params.topdiameter/2;
  var bottomradius = params.bottomdiameter/2;
  var halfthickness = params.thickness/2;
  topradius += halfthickness;
  bottomradius += halfthickness;
  
  var roundness = params.roundness;
  if(params.rounded != 1)
  {
    roundness = 0;
  }
  roundness = Math.min(roundness, halfthickness-0.1, params.width/2-0.1);
  if(roundness < 0) roundness = 0;
  
  var clampfactor = params.clampfactor / 100;
  if(clampfactor < 0) clampfactor = 0;
  if(clampfactor >= 1) clampfactor = 1;
  clampfactor *= (topradius-halfthickness)/topradius;  
  
  var topstartangle = - 180 * Math.acos(1 - 2*clampfactor) / Math.PI;
  var tophookcenter = new CSG.Vector2D(topradius, 0);
  var tophookstart = tophookcenter.plus(CSG.Vector2D.fromAngleDegrees(topstartangle).times(topradius));
  var circledistance = params.height - topradius - bottomradius - 2 * params.thickness;
  if(circledistance < 0) circledistance = 0;
  var bottomhookcenter = new CSG.Vector2D(-bottomradius, -circledistance);
  var gravityangle = 90 - tophookcenter.minus(bottomhookcenter).angleDegrees();
  
  var path = new CSG.Path2D();

  // top hook curve:
  if(params.cliplength > 0)
  {
    var clipstart = new CSG.Vector2D([0, -1]).times(params.cliplength).plus(tophookstart);
    path = path.appendPoint(clipstart);
  }
  var topcurvepath = CSG.Path2D.arc({
    center: tophookcenter,
    radius: topradius,
    startangle: topstartangle,
    endangle: 180,
    resolution: pathresolution,
    maketangent: true
  });
  path = path.concat(topcurvepath);

  // straight middle part:
  if(circledistance > 0)
  {
    path = path.appendPoint([0, -circledistance]);
  }
  
  // bottom hook curve:
  var bottomcurvepath = CSG.Path2D.arc({
    center: bottomhookcenter,
    radius: bottomradius,
    startangle: 0,
    endangle: -180-gravityangle,
    resolution: pathresolution,
    maketangent: true
  });
  path = path.concat(bottomcurvepath);
  
  // center around origin, and rotate as it would hang under gravity:
  var centerpoint = tophookcenter.plus(bottomhookcenter).times(0.5);  
  var matrix = CSG.Matrix4x4.translation(centerpoint.negated().toVector3D(0));
  matrix = matrix.multiply(CSG.Matrix4x4.rotationZ(gravityangle));
  path = path.transform(matrix);

  // extrude the path to create a 3D solid
  var hook = path.rectangularExtrude(2*(halfthickness-roundness), params.width-2*roundness, pathresolution, true);
  hook = hook.translate([0, 0, -params.width/2+roundness]);
  
  // expand to create rounded corners:
  if(roundness > 0)
  {
    hook = hook.expand(roundness, expandresolution);
  }
  // hook = hook.toPointCloud(0.1);
  
  // determine how many objects will fit in the build area:
  var bounds = hook.getBounds();
  var objsize = bounds[1].minus(bounds[0]);
  var margin = 5; // distance between the copies
  var numx = Math.floor((params.buildwidth + margin) / (objsize.x + margin));  
  var numy = Math.floor((params.builddepth + margin) / (objsize.y + margin));
  if(numx < 1) numx = 1;  
  if(numy < 1) numy = 1;

  // and make the copies:
  var result = new CSG();
  for(var x = 0; x < numx; x++)
  {
    var deltax = ((1-numx)/2+x) * (objsize.x + margin); 
    var colresult = new CSG();
    for(var y = 0; y < numy; y++)
    {
      var deltay = ((1-numy)/2+y) * (objsize.y + margin);
      var translated = hook.translate(new CSG.Vector3D(deltax, deltay, 0));
      colresult = colresult.union(translated); 
    }
    result = result.union(colresult);
  }    
   
  if(OpenJsCad.log) OpenJsCad.log("finish");
  return result;
}