diff --git a/fcad/align.scad b/fcad/align.scad new file mode 100644 index 0000000..83e8bd8 --- /dev/null +++ b/fcad/align.scad @@ -0,0 +1,29 @@ +function fAlign(modelA, coordNameA, modelB, coordNameB) = ( + let(coordA = fModelCoord(modelA, coordNameA), + coordB = fModelCoord(modelB, coordNameB), + translation = fCoordTranslation(coordA) - fCoordTranslation(coordB), + rotation = fCoordRotation(coordA) - fCoordRotation(coordB), + scale = fCoordScale(coordA) - fCoordScale(coordB)) + fUnion( + modelA, + fTranslate( + fRotate(modelB, coordNameB, rotation), + translation + ) + ) +); + +function fAttach(modelA, coordNameA, modelB, coordNameB) = ( + let(coordA = fModelCoord(modelA, coordNameA), + coordB = fModelCoord(modelB, coordNameB), + translation = fCoordTranslation(coordA) - fCoordTranslation(coordB), + rotation = fCoordRotation(coordA) - (-1 * fCoordRotation(coordB)), + scale = fCoordScale(coordA) - fCoordScale(coordB)) + fUnion( + modelA, + fTranslate( + fRotate(modelB, coordNameB, rotation), + translation + ) + ) +); diff --git a/fcad/coord.scad b/fcad/coord.scad index 08ab285..236e516 100644 --- a/fcad/coord.scad +++ b/fcad/coord.scad @@ -35,3 +35,11 @@ function fCoordRotation(coord) = ( function fCoordScale(coord) = ( fMapLookup(fKeyScale, coord) ); + +function fCoordInverse(coord) = ( + fCoord( + translation=[0, 0, 0] - fCoordTranslation(coord), + rotation=[180, 180, 180] + fCoordRotation(coord), + scale=1 / fCoordScale(coord) + ) +); diff --git a/fcad/cube.scad b/fcad/cube.scad index 0297ccf..a00cc57 100644 --- a/fcad/cube.scad +++ b/fcad/cube.scad @@ -13,8 +13,14 @@ function fCube(dims) = ( [1, 3, 7, 5], // +z ], coords=[ - [ "/x+,/y+,-z+", fCoord(translation=[x / 2, y / 2, 0]) ], - [ "/x+,/y+,+z+", fCoord(translation=[x / 2, y / 2, z]) ], + [ "-x-,/y-,/z-", fCoord(translation=[ 0, y / 2, z / 2], rotation=[ 0, -90, 0]) ], + [ "+x+,/y+,/z+", fCoord(translation=[ x, y / 2, z / 2], rotation=[ 0, 90, 0]) ], + + [ "/x-,-y-,/z-", fCoord(translation=[x / 2, 0, z / 2], rotation=[-90, 0, 0]) ], + [ "/x+,+y+,/z+", fCoord(translation=[x / 2, y, z / 2], rotation=[ 90, 0, 0]) ], + + [ "/x-,/y-,-z-", fCoord(translation=[x / 2, y / 2, 0], rotation=[180, 0, 180]) ], + [ "/x+,/y+,+z+", fCoord(translation=[x / 2, y / 2, z], rotation=[ 0, 0, 0]) ], ] ) ); diff --git a/fcad/cylinder.scad b/fcad/cylinder.scad index 4efba0a..cfe54d5 100644 --- a/fcad/cylinder.scad +++ b/fcad/cylinder.scad @@ -19,6 +19,9 @@ function fCylinder(h, r, r1=undef, r2=undef, sides=36) = ( // sides [for (side = side_range) [for (vertex = [2, 3, 1, 0]) (side * 2 + vertex) % (sides * 2)]] - ) + ), + coords=[ + [ "start", fCoord() ], + ] ) ); diff --git a/fcad/draw.scad b/fcad/draw.scad index fd216f4..ecda182 100644 --- a/fcad/draw.scad +++ b/fcad/draw.scad @@ -1,25 +1,3 @@ module fDraw(model) { polyhedron(points=fModelPoints(model), faces=fModelFaces(model)); } - -module fDrawN(model, scales) { - fDraw(model); - points = fModelPoints(model); - model_max = fMaxPoint(model); - translation = - [for (axis = [0 : 2]) - scales[axis] * model_max[axis]]; - translate(translation) children(); -} - -module fDrawX(model) { - fDrawN(model, [1, 0, 0]) children(); -} - -module fDrawY(model) { - fDrawN(model, [0, 1, 0]) children(); -} - -module fDrawZ(model) { - fDrawN(model, [0, 0, 1]) children(); -} diff --git a/fcad/fcad.scad b/fcad/fcad.scad index 5014736..7d868ae 100644 --- a/fcad/fcad.scad +++ b/fcad/fcad.scad @@ -1,10 +1,12 @@ +include ; include ; include ; include ; include ; include ; include ; -include ; +include ; include ; include ; include ; +include ; diff --git a/fcad/math.scad b/fcad/math.scad index 8d22bf6..ad7edfd 100644 --- a/fcad/math.scad +++ b/fcad/math.scad @@ -6,4 +6,3 @@ function fCartesianProduct(vecs) = ( for (val2 = fCartesianProduct(fVectorSlice(vecs, start=1))) concat(val1, val2)] ); - diff --git a/fcad/model.scad b/fcad/model.scad index cfb33b1..744db31 100644 --- a/fcad/model.scad +++ b/fcad/model.scad @@ -4,6 +4,13 @@ /// fKeyFaces "faces" fModelFaces(): [ [ pointIdx, ... ], ... ] /// fKeyCoords "coords" fModelCoords(): [ [ name, coord ], ... ] +/// OpenSCAD uses right-handed coordinates. We name directions on these axes: +/// X: left (-), right (+) +/// Y: back (-), front (+) +/// Z: bottom (-), top (+) +/// Coordinate systems that attach to surfaces should generally have the Z axis +/// normal to the surface. +/// /// Standard model coords names: /// /// [-/+] edge ("/" is midpoint) @@ -39,15 +46,15 @@ function fModelFaces(model) = ( ); fCoordAliases = [ - [ "bottom", "/x+,/y+,-z-" ], + [ "left", "-x-,/y-,/z-" ], + [ "right", "+x+,/y+,/z+" ], + + [ "back", "/x-,-y-,/z-" ], + [ "front", "/x+,+y+,/z+" ], + + [ "bottom", "/x-,/y-,-z-" ], [ "top", "/x+,/y+,+z+" ], - [ "back", "-x-,/y+,/z+" ], - [ "front", "+x+,/y+,/z+" ], - - [ "left", "/x+,-y-,/z+" ], - [ "right", "/x+,+y+,/z+" ], - [ "center", "/x+,/y+,/z+" ], ]; diff --git a/fcad/model_util.scad b/fcad/model_util.scad deleted file mode 100644 index 6d19dce..0000000 --- a/fcad/model_util.scad +++ /dev/null @@ -1,19 +0,0 @@ -function fMinPoint(model) = ( - [for (axis = [0 : 2]) - min([for (point = fModelPoints(model)) point[axis]])] -); - -function fMaxPoint(model) = ( - [for (axis = [0 : 2]) - max([for (point = fModelPoints(model)) point[axis]])] -); - -function fCenterPoint(model) = ( - let(model_min = fMinPoint(model), - model_max = fMaxPoint(model), - model_size = - [for (axis = [0 : 2]) - model_max[axis] - model_min[axis]]) - [for (axis = [0 : 2]) - model_min[axis] + (model_size[axis] / 2)] -); diff --git a/fcad/rotate.scad b/fcad/rotate.scad new file mode 100644 index 0000000..af87148 --- /dev/null +++ b/fcad/rotate.scad @@ -0,0 +1,45 @@ +function fRotate(model, coordName, rotation) = ( + // Shift the coordinate frame to the origin, rotate, then restore + let(coord = fModelCoord(model, coordName), + inverseCoord = fCoordInverse(coord), + zeroed = fTranslate(model, fCoordTranslation(inverseCoord)), + xMatrix = fRotationMatrixX(rotation[0]), + yMatrix = fRotationMatrixY(rotation[1]), + zMatrix = fRotationMatrixZ(rotation[2])) + fTranslate( + fModel( + points= + [for (point = fModelPoints(zeroed)) + ([point] * xMatrix * yMatrix * zMatrix)[0]], + faces=fModelFaces(model), + coords=fModelCoords(model) + ), + fCoordTranslation(coord) + ) +); + +// These matrices are transposed because we apply them with post-multiplication +// to work around OpenSCAD bugs. +function fRotationMatrixX(theta) = ( + [ + [ 1, 0, 0 ], + [ 0, cos(theta), sin(theta) ], + [ 0, -sin(theta), cos(theta) ], + ] +); + +function fRotationMatrixY(theta) = ( + [ + [ cos(theta), 0, -sin(theta) ], + [ 0, 1, 0 ], + [ sin(theta), 0, cos(theta) ], + ] +); + +function fRotationMatrixZ(theta) = ( + [ + [ cos(theta), sin(theta), 0 ], + [ -sin(theta), cos(theta), 0 ], + [ 0, 0, 1 ], + ] +); diff --git a/fcad/translate.scad b/fcad/translate.scad index 797387a..5fe169a 100644 --- a/fcad/translate.scad +++ b/fcad/translate.scad @@ -2,49 +2,8 @@ function fTranslate(model, translation) = ( fModel( points= [for (point = fModelPoints(model)) - [for (axis = [0 : 2]) - point[axis] + translation[axis]] - ], - faces=fModelFaces(model) + point + translation], + faces=fModelFaces(model), + coords=fModelCoords(model) ) ); - -function fZeroN(model, scales) = ( - let(model_min = fMinPoint(model), - translation = - [for (axis = [0 : 2]) - scales[axis] * model_min[axis]]) - fTranslate(model, translation) -); - -function fZeroX(model) = ( - fZeroN(model, [-1, 0, 0]) -); - -function fZeroY(model) = ( - fZeroN(model, [0, -1, 0]) -); - -function fZeroZ(model) = ( - fZeroN(model, [0, 0, -1]) -); - -function fCenterN(model, scales) = ( - let(model_center = fCenterPoint(model), - translation = - [for (axis = [0 : 2]) - scales[axis] * model_center[axis]]) - fTranslate(model, translation) -); - -function fCenterX(model) = ( - fCenterN(model, [-1, 0, 0]) -); - -function fCenterY(model) = ( - fCenterN(model, [0, -1, 0]) -); - -function fCenterZ(model) = ( - fCenterN(model, [0, 0, -1]) -); diff --git a/fcad/union.scad b/fcad/union.scad new file mode 100644 index 0000000..aaaf9f4 --- /dev/null +++ b/fcad/union.scad @@ -0,0 +1,10 @@ +function fUnion(modelA, modelB) = ( + let(numPointsA = len(fModelPoints(modelA))) + fModel( + points=concat(fModelPoints(modelA), fModelPoints(modelB)), + faces=concat(fModelFaces(modelA), + [for (face = fModelFaces(modelB)) + [for (point = face) point + numPointsA]]) + ) + // TODO: how should we handle coords here? +); diff --git a/test.scad b/test.scad index f331ef9..6ac65fe 100644 --- a/test.scad +++ b/test.scad @@ -1,5 +1,21 @@ use ; -fDrawX(fCylinder(10, r1=5, r2=2)) -fDrawX(fSphere(10)) -fDrawX(fCube(10)); \ No newline at end of file +module testAxes(translation=[0, 0, 0], rotation=[0, 0, 0]) { + color("red") fDraw(fTranslate(fRotate(fRotate(fCylinder(h=100, r=1), "start", [0, 90, 0]), "start", rotation), translation)); + color("green") fDraw(fTranslate(fRotate(fRotate(fCylinder(h=100, r=1), "start", [-90, 0, 0]), "start", rotation), translation)); + color("blue") fDraw(fTranslate(fRotate(fRotate(fCylinder(h=100, r=1), "start", [0, 0, 0]), "start", rotation), translation)); +} + +testAxes(translation=[0, 0, 200], rotation=[0, 0, 0]); +testAxes(translation=[200, 0, 0], rotation=[0, 180, ]); +testAxes(translation=[0, 0, -200], rotation=[180, 0, 0]); +testAxes(translation=[-200, 0, 0], rotation=[0, -90, 0]); +testAxes(translation=[0, 200, 0], rotation=[-90, 0, 0]); +testAxes(translation=[0, -200, 0], rotation=[90, 0, 0]); + + +//result = fAttach(fCube(10), "top", fCube(5), "bottom5"); +//result = fRotate(fCube(5), "front", [0, 360, 360]); + +//echo(result); +//#fDraw(result); \ No newline at end of file