I've finished a script that converts SL in golly to tile code in OpenJSCAD, and also reports the BOM of the tiles.
1. Copy it to some directory under golly python.
2. Make sure you have SL only in golly.
3. Run the script. You get the report of each tile quantity, total, and script to generate the tiles.
4. In the same folder of the script, find tiles.txt file, this is jscad script.
5. Add it content to the end of posted below jscad script.
6. Run jscad (shift+enter)
7. Have your SL in tiles.
Code: Select all
import golly as g
def FindTiles(list, validTiles, tilesUseLimit, result):
if len(list) == 0:
return True
for j in xrange(len(validTiles)):
v = validTiles[j]
if tilesUseLimit[j] < 1 or len(v) > len(list):
continue
fail = False
for i in xrange(len(v)):
if v[i] != list[i]:
fail = True
break
if not fail:
newlist = []
for i in xrange(len(v), len(list)):
newlist.append(list[i])
result.append(j)
tilesUseLimit[j] -= 1
if j > 0:
tilesUseLimit[j - 1] -= 1
if j + 1 < len(tilesUseLimit):
tilesUseLimit[j + 1] -= 1
if not FindTiles(newlist, validTiles, tilesUseLimit, result):
result.pop()
tilesUseLimit[j] += 1
if j > 0:
tilesUseLimit[j - 1] += 1
if j + 1 < len(tilesUseLimit):
tilesUseLimit[j + 1] += 1
else:
return True
return False
def FindTilesCircular(list, tiles, tilesUseLimit):
for i in xrange(8):
result = []
newlist = []
for j in xrange(len(list)):
newlist.append(list[(i + j) % len(list)])
if FindTiles(newlist, tiles, tilesUseLimit, result):
return (i, result)
def UpdateBom(x, y, bom, addCentral, filled, con, empty0, empty4, excon):
neighbohrs = [(0, -1), (1, -1), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1)]
list = []
total = 0
for i, j in neighbohrs:
list.append(g.getcell(x + i, y + j))
if g.getcell(x + i, y + j) == 1:
total += 1
if g.getcell(x, y) == 1:
if total == 2:
bom[0] += 1
tiles = [[0,0,0,1], [1,0,0,0], [0,0,1,0], [0,1,0,0], [0,1,0,1], [1,0,1,0], [0,0,1,1], [1,1,0,0]]
tilesUseLimit = [100, 100, 100, 100, 100, 100, 100, 100]
tilesIdx = [5, 5, 6, 6, 7, 7, 8, 8]
i, res = FindTilesCircular(list, tiles, tilesUseLimit)
if total == 2:
con.append([x, y, 0, i])
di = i
for r in res:
bom[tilesIdx[r]] += 1
filled.append([x, y, r, di])
di += len(tiles[r])
#Dead cell
else:
if total <= 2:
bom[12] += 1
tiles = [[0,0,0,0], [0,0,1,0], [0,1,0,0], [0,0,0,1], [1,0,0,0]]
tilesUseLimit = [100, 100, 100, 100, 100]
tilesIdx = [13, 14, 14, 15, 15]
i, res = FindTilesCircular(list, tiles, tilesUseLimit)
di = i
for r in res:
bom[tilesIdx[r]] += 1
empty0.append([x, y, r, di])
di += len(tiles[r])
con.append([x, y, 12, i])
# total >= 4
else:
bom[4] += 1
tiles = [[1,1,0,0], [0,0,1,1], [1,0], [0,1], [1, 1]]
tilesUseLimit = [100, 100, 100, 100, 100]
tilesIdx = [9, 9, 10, 10, 11]
i, res = FindTilesCircular(list, tiles, tilesUseLimit)
di = i
for r in res:
bom[tilesIdx[r]] += 1
empty4.append([x, y, r, di])
di += len(tiles[r])
con.append([x, y, 4, i])
if addCentral:
totalConnectors = 0
firstIdx = -1
first0Idx = -1
firstCon = -1
neighbohrs = [(0, 0), (0, -1), (1, -1), (1, 0)]
cnt = 0
for i, j in neighbohrs:
if g.getcell(x + i, y + j) > 0:
totalConnectors+=1
if firstIdx == -1:
firstIdx = cnt
i1, j1 = neighbohrs[(cnt + 1) % 4]
if g.getcell(x + i1, y + j1) > 0:
firstCon = cnt
else:
if first0Idx == -1 :
first0Idx = cnt
cnt += 1
if totalConnectors == 0:
bom[12] += 1
excon.append([x, y, 12, 0])
if totalConnectors == 1:
bom[1] += 1
excon.append([x, y, 1, firstIdx])
if totalConnectors == 2:
if list[0] == list[2]:
bom[0] += 1
excon.append([x, y, 0, firstIdx])
else:
bom[3] += 1
excon.append([x, y, 3, firstCon])
if totalConnectors == 3:
bom[2] += 1
excon.append([x, y, 2, first0Idx])
if totalConnectors == 4:
bom[4] += 1
excon.append([x, y, 4, firstIdx])
bom = [0 for i in xrange(16)]
rect = g.getrect()
filled = []
con = []
empty0 = []
empty4 = []
excon = []
for i in xrange(rect[0] - 1, rect[0] + rect[2] + 1):
for j in xrange(rect[1] - 1, rect[1] + rect[3] + 1):
UpdateBom(i,j,bom, i != rect[0] + rect[2] and j != rect[1] - 1, filled, con, empty0, empty4, excon)
f = open("tiles.txt",'w')
for fil in filled:
f.write("PlaceFilled(%d,%d,%d,%d);\n" % (fil[0], -fil[1], fil[2], fil[3]))
for fil in con:
f.write("PlaceInternalConnector(%d,%d,%d,%d);\n" % (fil[0], -fil[1], fil[2], fil[3]))
for fil in excon:
f.write("PlaceExternalConnector(%d,%d,%d,%d);\n" % (fil[0], -fil[1], fil[2], fil[3]))
for fil in empty0:
f.write("PlaceEmpty0(%d,%d,%d,%d);\n" % (fil[0], -fil[1], fil[2], fil[3]))
for fil in empty4:
f.write("PlaceEmpty4(%d,%d,%d,%d);\n" % (fil[0], -fil[1], fil[2], fil[3]))
f.close()
total = 0
for i in bom:
total += i
g.show("Total = " + str(total) + " , BOM = " + str(bom))
Code: Select all
//!OpenSCAD
//main parameters
emptyToothWidth = 0.4;
emptyToothLength = 0.1;
filledToothWidth = 0.58;
//3d structural teeth
cubeSizeW = 0.17;
cubeAngle = 30;
toothLocation = 0.07;
//Adding 3d tooths flag
add3dStructure = false;
//Height
H = 1;
r = 10;
d = r * cos(45 / 2);
side = 2 * r * sin(45 / 2);
eps = 0.001;
module Tooth()
{
translate([0, 0, -H / 2])rotate([90, 0, 0])linear_extrude(height = cubeSizeW * r) polygon([[-eps,-eps], [-eps ,H / 2],[H / 2 * sin(cubeAngle), -eps]]);
}
module Slice(use3D = true, r1 = r)
{
if(use3D && add3dStructure)
{
difference()
{
union()
{
linear_extrude(height = H) rotate([0,0,-45/2])polygon([[0,0],[r1, 0],[r1 * cos(360/8), r1* sin(360/8)]] );
translate([d, - side * toothLocation, H / 2]) Tooth();
translate([d, side * toothLocation, H / 2]) rotate([180, 0, 0]) Tooth();
}
translate([d, - side * toothLocation, H / 2]) rotate([0, 180, 0]) Tooth();
translate([d, side * toothLocation, H / 2]) rotate([180, 180, 0]) Tooth();
}
}
else
{
linear_extrude(height = H) rotate([0,0,-45/2])polygon([[0,0],[r, 0],[r * cos(360/8), r* sin(360/8)]] );
}
};
module SliceWithTooth()
{
union()
{
Slice(false);
linear_extrude(height = H) translate([d, -r * emptyToothWidth / 2]) square([r * emptyToothLength,r * emptyToothWidth]);
}
};
//Tiles from slices
module SquareTilePiece()
{
difference()
{
union()
{
linear_extrude(height = H) polygon([[0,0], [side/2,side/2], [side/2,-side/2]]);
if(add3dStructure)
{
translate([side / 2, - side * toothLocation, H / 2]) Tooth();
translate([side / 2, side * toothLocation, H / 2]) rotate([180, 0, 0]) Tooth();
}
}
if(add3dStructure)
{
translate([side / 2, - side * toothLocation, H / 2]) rotate([0, 180, 0]) Tooth();
translate([side / 2, side * toothLocation, H / 2]) rotate([180, 180, 0]) Tooth();
}
}
}
module SquareTile()
{
rotate([0,0,45/2])union()
{
SquareTilePiece();
rotate([0,0,90]) SquareTilePiece();
rotate([0,0,180]) SquareTilePiece();
rotate([0,0,-90]) SquareTilePiece();
}
};
module EmptyTile0_NoTeeth()
{
difference()
{
union()
{
Slice();
rotate([0,0,45]) Slice();
rotate([0,0,90]) Slice();
rotate([0,0,135]) Slice();
}
SquareTile();
}
};
module EmptyTile0_EdgeTeeth()
{
difference()
{
union()
{
SliceWithTooth();
rotate([0,0,45]) Slice();
rotate([0,0,90]) Slice();
rotate([0,0,135]) Slice();
}
SquareTile();
}
};
module EmptyTile0_InternalTeeth()
{
difference()
{
union()
{
Slice();
rotate([0,0,45]) SliceWithTooth();
rotate([0,0,90]) Slice();
rotate([0,0,135]) Slice();
}
SquareTile();
}
};
//Simple Living parts
module LiveSlice()
{
r1 = (r * cos(45/2) - emptyToothLength * r) / cos(45/2);
color([0, 0.4, 0.9]) linear_extrude(height = H) rotate([0,0,-45/2])polygon([[0,0],[r1, 0],[r1 * cos(360/8), r1 * sin(360/8)]] );
};
module LiveSliceWithTooth()
{
size = r/6;
dtooth = r * filledToothWidth;
color([0, 0.4, 0.9]) union()
{
LiveSlice();
linear_extrude(height = H)translate([r * cos(45/2) - size, -dtooth /2])square([size,dtooth ]);
}
};
module HelperLife_InternalTooth()
{
rotate([0,0,45])
union()
{
LiveSliceWithTooth();
rotate([0,0,45]) LiveSliceWithTooth();
rotate([0,0,-45]) LiveSliceWithTooth();
}
};
module TileLife_InternalTooth()
{
rotate([0,0,45/2])
color([0, 0.4, 0.9])
difference()
{
linear_extrude(height = H)polygon([[-d, d], [-d, -d], [d, -d], [d, d]]);
translate([-d, -d]) HelperLife_InternalTooth();
translate([d, -d]) rotate([0,0,90]) HelperLife_InternalTooth();
translate([-d, d]) rotate([0,0,-90]) HelperLife_InternalTooth();
translate([d, d]) rotate([0,0,180]) HelperLife_InternalTooth();
translate([d - filledToothWidth * r / 2, -d/2])cube([side, side, H]);
translate([-side -d + filledToothWidth * r / 2, -d/2])cube([side, side, H]);
translate([-d/2, -side -d + filledToothWidth * r / 2 ])cube([side, side, H]);
translate([-d/2, d - filledToothWidth * r / 2 ])cube([side, side, H]);
}
};
module TileSpaceFiller_Type4()
{
rotate([0,0,-45/2])
color([0, 0.4, 0.9])
difference()
{
linear_extrude(height = H) polygon([[-side, side], [-side, -side], [side, -side], [side, side]]);
translate([d, -d]) rotate([0,0,45 + 135]) SliceWithTooth() ;
translate([d, -d]) rotate([0,0,45 + 90]) Slice() ;
translate([d, -d]) rotate([0,0,45 + 45]) SliceWithTooth() ;
translate([d, d]) rotate([0,0,45 + 180])LiveSliceWithTooth() ;
translate([d, d]) rotate([0,0,45 + 135 ])LiveSlice() ;
translate([d, d]) rotate([0,0,45 + -135])LiveSlice() ;
translate([-d, d]) rotate([0,0,45 + -45]) SliceWithTooth() ;
translate([-d, d]) rotate([0,0,45 + -90]) Slice() ;
translate([-d, d]) rotate([0,0,45 + -135]) SliceWithTooth();
translate([-d, -d])rotate([0,0,45]) LiveSliceWithTooth() ;
translate([-d,-d]) rotate([0,0,45 + 45])LiveSlice() ;
translate([-d, -d]) rotate([0,0,45 + -45])LiveSlice() ;
}
};
module TileSpaceFiller_Type3()
{
rotate([0,0,-45/2])
color([0, 0.4, 0.9])
difference()
{
linear_extrude(height = H) polygon([[-side, side], [-side, -side], [side, -side], [side, side]]);
translate([d, -d]) rotate([0,0,45 + 135]) LiveSlice() ;
scale(1 + eps)translate([d, -d]) rotate([0,0,45 + 90]) LiveSlice() ;
translate([d, -d]) rotate([0,0,45 + 45]) LiveSlice() ;
translate([d, d]) rotate([0,0,90 + 180])SliceWithTooth() ;
scale(1 + eps)translate([d, d]) rotate([0,0,45 + 180])Slice() ;
translate([d, d]) rotate([0,0,45 + 135])Slice() ;
translate([-d, d]) rotate([0,0,45 + -45]) Slice() ;
scale(1 + eps)translate([-d, d]) rotate([0,0,45 + -90]) SliceWithTooth() ;
translate([-d, d]) rotate([0,0,45 + -135]) Slice();
translate([-d,-d]) rotate([0,0,45 + 45])Slice() ;
scale(1 + eps)translate([-d, -d])rotate([0,0,45]) Slice() ;
translate([-d, -d]) rotate([0,0,45 + -45])SliceWithTooth() ;
}
};
module TileSpaceFiller_Type2()
{
rotate([0,0,-45/2])
color([0, 0.4, 0.9])
difference()
{
linear_extrude(height = H) polygon([[-side, side], [-side, -side], [side, -side], [side, side]]);
translate([d, -d]) rotate([0,0,45 + 135]) LiveSliceWithTooth() ;
scale(1 + eps)translate([d, -d]) rotate([0,0,45 + 90]) LiveSlice() ;
translate([d, -d]) rotate([0,0,45 + 45]) LiveSlice() ;
translate([d, d]) rotate([0,0,90 + 180])SliceWithTooth() ;
scale(1 + eps)translate([d, d]) rotate([0,0,45 + 180])SliceWithTooth() ;
translate([d, d]) rotate([0,0,45 + 135])Slice() ;
translate([-d, d]) rotate([0,0,45 + -45]) Slice() ;
scale(1 + eps)translate([-d, d]) rotate([0,0,45 + -90]) SliceWithTooth() ;
translate([-d, d]) rotate([0,0,45 + -135]) SliceWithTooth();
translate([-d,-d]) rotate([0,0,45 + 45])LiveSlice() ;
scale(1 + eps)translate([-d, -d])rotate([0,0,45]) LiveSlice() ;
translate([-d, -d]) rotate([0,0,45 + -45])LiveSliceWithTooth() ;
}
};
module TileSpaceFiller_Type1()
{
rotate([0,0,-45/2])
color([0, 0.4, 0.9])
difference()
{
linear_extrude(height = H) polygon([[-side, side], [-side, -side], [side, -side], [side, side]]);
translate([d, -d]) rotate([0,0,45 + 135]) SliceWithTooth() ;
scale(1 + eps)translate([d, -d]) rotate([0,0,45 + 90]) SliceWithTooth() ;
translate([d, -d]) rotate([0,0,45 + 45]) SliceWithTooth() ;
translate([d, d]) rotate([0,0,90 + 180])LiveSlice() ;
scale(1 + eps)translate([d, d]) rotate([0,0,45 + 180])LiveSliceWithTooth() ;
translate([d, d]) rotate([0,0,45 + 135])LiveSliceWithTooth() ;
translate([-d, d]) rotate([0,0,45 + -45]) LiveSliceWithTooth() ;
scale(1 + eps)translate([-d, d]) rotate([0,0,45 + -90]) LiveSlice() ;
translate([-d, d]) rotate([0,0,45 + -135]) LiveSliceWithTooth();
translate([-d,-d]) rotate([0,0,45 + 45])LiveSliceWithTooth() ;
scale(1 + eps)translate([-d, -d])rotate([0,0,45]) LiveSliceWithTooth() ;
translate([-d, -d]) rotate([0,0,45 + -45])LiveSlice() ;
}
};
//Tiles with complex negatives
module TileLife_EmptyInternalEdgeTooth()
{
color([0, 0.4, 0.9])
difference()
{
union()
{
LiveSliceWithTooth();
rotate([0,0,45]) LiveSlice();
rotate([0,0,90]) LiveSlice();
rotate([0,0,135]) LiveSlice();
}
//rotate([0,0,45]) TileLife_InternalTooth();
rotate([0,0,45]) TileSpaceFiller_Type4();
}
};
module TileLife_EmptyInternalTooth()
{
color([0, 0.4, 0.9])
difference()
{
union()
{
rotate([0,0,45]) LiveSliceWithTooth();
LiveSlice();
rotate([0,0,90]) LiveSlice();
rotate([0,0,135]) LiveSlice();
}
//rotate([0,0,45]) TileLife_InternalTooth();
rotate([0,0,45]) TileSpaceFiller_Type4();
}
};
module TileLife_FilledInternalEdgeTooth()
{
color([0, 0.4, 0.9])
union()
{
union()
{
LiveSliceWithTooth();
rotate([0,0,45]) LiveSlice();
rotate([0,0,90]) LiveSliceWithTooth();
rotate([0,0,135]) LiveSlice();
}
//rotate([0,0,45]) TileSpaceFiller_Type4();
rotate([0,0,45]) TileSpaceFiller_Type4();
}
};
module TileLife_FilledInternalTooth()
{
color([0, 0.4, 0.9])
union()
{
union()
{
LiveSliceWithTooth();
rotate([0,0,45]) LiveSliceWithTooth();
rotate([0,0,90]) LiveSlice();
rotate([0,0,135]) LiveSlice();
}
//rotate([0,0,45]) TileLife_InternalTooth();
rotate([0,0,45]) TileSpaceFiller_Type4();
}
};
module EmptyTile4_2teeth_90()
{
difference()
{
union()
{
SliceWithTooth();
rotate([0,0,45]) SliceWithTooth();
}
TileLife_InternalTooth();
}
};
module EmptyTile4_1teeth_90()
{
difference()
{
union()
{
Slice();
rotate([0,0,45]) SliceWithTooth();
}
TileLife_InternalTooth();
}
};
module EmptyTile4_2teeth_180()
{
difference()
{
union()
{
Slice();
rotate([0,0,45]) Slice();
rotate([0,0,90]) SliceWithTooth();
rotate([0,0,135]) SliceWithTooth();
}
TileLife_InternalTooth();
}
};
module PlaceFilled(x, y, type, rot)
{
dx =- 0.1 * sin(-45 - 45 * rot);
dy =- 0.1 * cos(-45 - 45 * rot);
scalefactor1 = 0.99;
scalefactor2 = 0.98;
if(type == 0)
translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,-45 - 45 * rot])TileLife_EmptyInternalEdgeTooth();
if(type == 1)
translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor1) rotate([0,180, -90 - 45 * rot])TileLife_EmptyInternalEdgeTooth();
if(type == 2)
translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,-45 - 45 * rot])TileLife_EmptyInternalTooth();
if(type == 3)
translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor1) rotate([0,180, -90 - 45 * rot])TileLife_EmptyInternalTooth();
if(type == 4)
translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,-45 - 45 * rot]) TileLife_FilledInternalEdgeTooth();
if(type == 5)
translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor2) rotate([0,180, -90 - 45 * rot])TileLife_FilledInternalEdgeTooth();
if(type == 6)
translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,-45 - 45 * rot]) TileLife_FilledInternalTooth();
if(type == 7)
translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor2) rotate([0,180, -90 - 45 * rot])TileLife_FilledInternalTooth();
};
module PlaceInternalConnector(x, y, type, rot)
{
dx =- 0.1 * sin(-45 - 45 * rot);
dy =- 0.1 * cos(-45 - 45 * rot);
scalefactor1 = 0.97;
scalefactor2 = 0.94;
if(type == 0)
translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,- 45 * rot])TileSpaceFiller_Type4();
if(type == 12)
color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,45 - 45 * rot])SquareTile();
if(type == 4)
color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,45 - 45 * rot])TileLife_InternalTooth();
}
module PlaceExternalConnector(x, y, type, rot)
{
dx =- 0.1 * sin(-45 - 45 * rot);
dy =- 0.1 * cos(-45 - 45 * rot);
scalefactor1 = 0.97;
scalefactor2 = 0.94;
if(type == 0)
translate([d + 2 * d * x + dx, d + 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45/2 - 90 * rot])TileSpaceFiller_Type4();
if(type == 1)
color([0.8, 0.8, 0.2]) translate([d + 2 * d * x + dx, d + 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45/2 - 90 - 90 * rot])TileSpaceFiller_Type3();
if(type == 2)
color([0.8, 0.8, 0.2]) translate([d + 2 * d * x + dx, d + 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45/2 - 90 - 90 * rot])TileSpaceFiller_Type1();
if(type == 3)
color([0.8, 0.8, 0.2]) translate([d + 2 * d * x + dx, d + 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45/2 - 90 - 90 * rot])TileSpaceFiller_Type2();
if(type == 12)
color([0.8, 0.8, 0.2]) translate([d + 2 * d * x + dx, d + 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,45/2 - 45 * rot])SquareTile();
if(type == 4)
color([0, 0.4, 0.9]) translate([d +2 * d * x + dx, d +2 * d * y + dy]) scale(scalefactor2) rotate([0,0,-45/2 ])TileLife_InternalTooth();
}
module PlaceEmpty0(x, y, type, rot)
{
dx =- 0.1 * sin(-45 - 45 * rot);
dy =- 0.1 * cos(-45 - 45 * rot);
scalefactor1 = 0.98;
scalefactor2 = 0.98;
if(type == 0)
color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,-45 - 45 * rot])EmptyTile0_NoTeeth();
if(type == 1)
color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,-45 - 45 * rot])EmptyTile0_InternalTeeth();
if(type == 2)
color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor2) rotate([0,180, -90 - 45 * rot])EmptyTile0_InternalTeeth();
if(type == 3)
color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,-45 - 45 * rot])EmptyTile0_EdgeTeeth();
if(type == 4)
color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor2) rotate([0,180, -90 - 45 * rot])EmptyTile0_EdgeTeeth();
}
module PlaceEmpty4(x, y, type, rot)
{
dx =- 0.1 * sin(-45 - 45 * rot);
dy =- 0.1 * cos(-45 - 45 * rot);
scalefactor1 = 0.98;
scalefactor2 = 0.98;
if(type == 0)
color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,-45 - 45 * rot])EmptyTile4_2teeth_180();
if(type == 1)
color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor2) rotate([0,180, -90 - 45 * rot])EmptyTile4_2teeth_180();
if(type == 2)
color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45 - 45 * rot])EmptyTile4_1teeth_90();
if(type == 3)
color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor2) rotate([0,180, -90 - 45 * rot])EmptyTile4_1teeth_90();
if(type == 4)
color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45 - 45 * rot])EmptyTile4_2teeth_90();
}
I cheated a bit, I used two different colors for the "grey" symmetrical piece. The grey was somewhat ugly, but having the same piece in two colors I think is totally valid, and should not be considered two tiles.
I managed to see the Still life applet (your instructions helped to enable it in IE10). I think the most missing feature is copy rle or any format that can be used outside of it. As the applet itself I enjoyed it very much, especially the stabilize option.