Skip to content

Instantly share code, notes, and snippets.

@hrgdavor
Created January 23, 2021 12:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hrgdavor/c63e34f862aab00cf9253daf2e071812 to your computer and use it in GitHub Desktop.
Save hrgdavor/c63e34f862aab00cf9253daf2e071812 to your computer and use it in GitHub Desktop.
Configurable hypercube(tesseract) for 3D print
/*
Configurable hypercube(tesseract) https://en.wikipedia.org/wiki/Tesseract
Used it for 3D printing for a friend and to play with jscad.
@author Davor Hrg (https://github.com/hrgdavor)
*/
const {primitives, transforms, maths, extrusions, geometries} = require('@jscad/modeling')
const {translate, rotate, transform} = transforms
const {cylinder, sphere, circle} =primitives
const { extrudeFromSlices, slice, extrudeLinear } = extrusions
const { geom2, geom3, path2, poly2, poly3 } = geometries
const { mat4 } = maths
function getParameterDefinitions() {
return [
{name:'withStand',caption:'With stand', type:'checkbox', checked:true},
{name:'len1',caption:'Outer side', type:'int', initial:30},
{name:'len2',caption:'Inner side', type:'int', initial:15},
{name:'diameter',caption:'Thickness', type:'int', initial:3},
{name:'baseD',caption:'Base diameter', type:'int', initial:12, min:12},
{name:'baseH',caption:'Base height', type:'int', initial:4},
{name:'baseTh',caption:'Base thickness', type:'int', initial:1},
]
}
function main({withStand=1, diameter =1.5, baseD = 6, baseH = 4, baseTh=1,len1 = 30, len2 = 15}){
var baseR = baseD / 2
var radius = diameter /2
var offset1 = len1 / 2
var offset2 = len2 / 2
var hyperCube = [
..._square(len1,radius),
..._square(len2,radius),
...diagonals(offset1, offset2, radius, 1),
...diagonals(offset1, offset2, radius,-1),
]
var rot = rotationMatrixFromVectors([1,1,1],[0,0,1])
var step = (baseH - baseTh) / 5
var levels = [
[0,baseR/radius],
[baseTh,baseR/radius],
[0.001,2.4],
[step/2,2],
[step/2,1.6],
[step,1.3],
[step*2,1.1],
[step,1],
]
if(withStand){
return [
extrudeScaleLevels({levels, baseSlice: circle({radius})}),
translate([0,0,offset1*Math.sqrt(3)+baseH],transform(rot, hyperCube)),
]
}
return hyperCube
}
function diagonals(offset1, offset2, r, zDir=1){
return [
cylinderFromTo([-offset1,-offset1,offset1*zDir],[-offset2,-offset2,offset2*zDir],r),
cylinderFromTo([ offset1,-offset1,offset1*zDir],[ offset2,-offset2,offset2*zDir],r),
cylinderFromTo([ offset1, offset1,offset1*zDir],[ offset2, offset2,offset2*zDir],r),
cylinderFromTo([-offset1, offset1,offset1*zDir],[-offset2, offset2,offset2*zDir],r),
]
}
function _square(len1, r){
var offset = len1 / 2;
return [
...cylinderSq(offset, r, -offset),
...sphereSq(offset,r,-offset),
...cylinderSq(offset, r, offset),
...sphereSq(offset,r,offset),
...cylinderSqUp(offset, r, offset),
]
}
function cylinderSq(offset, r, z=0){
return [
cylinderFromTo([-offset,-offset,z],[ offset,-offset,z],r),
cylinderFromTo([-offset, offset,z],[ offset, offset,z],r),
cylinderFromTo([-offset, offset,z],[-offset,-offset,z],r),
cylinderFromTo([ offset, offset,z],[ offset,-offset,z],r),
]
}
function cylinderSqUp(offset, r, z=0){
return [
cylinderFromTo([-offset,-offset,-z],[-offset,-offset,z],r),
cylinderFromTo([-offset, offset,-z],[-offset, offset,z],r),
cylinderFromTo([ offset,-offset,-z],[ offset,-offset,z],r),
cylinderFromTo([ offset, offset,-z],[ offset, offset,z],r),
]
}
function sphereSq(offset, r, z=0){
return [
translate([-offset,-offset,z], sphere({radius:r})),
translate([-offset, offset,z], sphere({radius:r})),
translate([ offset, -offset,z], sphere({radius:r})),
translate([ offset, offset,z], sphere({radius:r})),
]
}
function cylinderFromTo(p1,p2, radius){
const sqr = x=>x*x
let dx = p2[0] - p1[0]
let dy = p2[1] - p1[1]
let dz = p2[2] - p1[2]
let height = Math.sqrt( sqr(dx) + sqr(dy) + sqr(dz))
let obj = cylinder({radius, height})
if(dx || dy){
let dxy = Math.sqrt( sqr(dx) + sqr(dy))
let ay = Math.atan(dxy/dz) *(dx < 0 ? -1:1)
let az = Math.atan(dy/dx)
let ax = dz < 0 ? -Math.PI:0
obj = rotate([ax,ay,az], obj)
}
let mid = [p1[0]+dx/2,p1[1]+dy/2,p1[2]+dz/2]
return translate(mid, obj)
}
function rotationMatrixFromVectors (srcVector, targetVector) {
// From https://gist.github.com/kevinmoran/b45980723e53edeb8a5a43c49f134724
srcVector = maths.vec3.normalize(srcVector)
targetVector = maths.vec3.normalize(targetVector)
const axis = maths.vec3.cross(targetVector, srcVector)
const cosA = maths.vec3.dot(targetVector, srcVector)
const k = 1 / (1 + cosA)
return maths.mat4.fromValues(
(axis[0] * axis[0] * k) + cosA, (axis[1] * axis[0] * k) - axis[2], (axis[2] * axis[0] * k) + axis[1], 0,
(axis[0] * axis[1] * k) + axis[2], (axis[1] * axis[1] * k) + cosA, (axis[2] * axis[1] * k) - axis[0], 0,
(axis[0] * axis[2] * k) - axis[1], (axis[1] * axis[2] * k) + axis[0], (axis[2] * axis[2] * k) + cosA, 0,
0, 0, 0, 1
)
}
const extrudeScaleLevels = ({levels, baseSlice, corners='edge', segments=16, tz=0, tx=0, ty=0}) => {
var h = 0;
baseSlice = slice.fromSides(geom2.toSides(baseSlice))
return extrudeFromSlices({numberOfSlices:levels.length, callback:(progress, counter)=>{
var level = levels[counter];
h += level[0];
var scaleX = scaleY = level[1];
if(level.length > 2) scaleY = level[2];
const scaleMatrix = mat4.fromScaling([scaleX, scaleY, 1])
const transformMatrix = mat4.fromTranslation([0, 0, h])
return slice.transform(mat4.multiply(scaleMatrix, transformMatrix), baseSlice)
}});
}
module.exports = {main, getParameterDefinitions}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment