1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
$fa = $preview ? 10 : 10; // 1;
$fs = $preview ? 0.2 : 0.2; // 0.01;
colors = [
"#df0000",
"#fb8721",
"#f1e100",
"#158f25",
"#2c3ee5",
"#7706af",
"#333333",
"#88502b",
"#5dccfb",
"#f0a67b",
"#ffffff"
];
wideR = 65;
braidScale = 5;
braidR = 12;
strands = len(colors);
strandGap = 3;
wideRes = $preview ? 180 : 360;
strandRes = $preview ? 36 : 180;
braidCircumference = 2 * PI * braidR;
strandR = (braidCircumference / strands - strandGap) / 2;
outermostCircumference = 2 * PI * (wideR + braidR);
strandH = outermostCircumference * wideRes / 360 + 0.1;
function rodriguesRotation(vector, axis, angle) =
vector * cos(angle) + cross(axis, vector) * sin(angle) + axis * (axis * vector) * (1 - cos(angle));
/*
these cross sections were always parallel to the Z axis,
but that’s not really correct
actual d/dwideT of center of braid is (-wideR sin wideT, wideR cos wideT, 0)
magnitude of that is wideR
absolute d/dwideT of center of strand is
(
-wideR sin wideT - braidR (braidScale cos wideT sin braidT + sin wideT cos braidT),
wideR cos wideT + braidR (-braidScale sin wideT sin braidT + cos wideT cos braidT),
braidR braidScale cos braidT
)
the Maxima CAS says that the magnitude of that is
sqrt(wideR² + 2wideRbraidR cos braidT + braidR²cos²braidT + braidR²braidScale²)
but actually OpenSCAD has a norm() function to get magnitudes anyway oops
strand plane basis is strand plane normal x braid center normal,
since we know those two vectors are never parallel with braidScale ≠ 0
*/
function point(wideT, strandI, strandT) =
let (
braidO = [wideR * cos(wideT), wideR * sin(wideT), 0],
braidPlaneNormal = [-wideR * sin(wideT), wideR * cos(wideT), 0],
braidPlaneNormalUnit = braidPlaneNormal / wideR,
braidT = wideT * braidScale - strandI * 360 / strands,
braidPlaneRel = [braidR * cos(braidT), braidR * sin(braidT)],
strandO = [braidO.x + braidPlaneRel.x * cos(wideT), braidO.y + braidPlaneRel.x * sin(wideT), braidPlaneRel.y],
strandPlaneNormal = [braidPlaneNormal.x - braidR * (braidScale * cos(wideT) * sin(braidT) + sin(wideT) * cos(braidT)), braidPlaneNormal.y + braidR * (-braidScale * sin(wideT) * sin(braidT) + cos(wideT) * cos(braidT)), braidR * braidScale * cos(braidT)],
strandPlaneNormalUnit = strandPlaneNormal / norm(strandPlaneNormal),
strandPlaneBasis = cross(strandPlaneNormalUnit, braidPlaneNormalUnit),
strandRelDir = rodriguesRotation(strandPlaneBasis, strandPlaneNormalUnit, strandT),
strandRel = strandRelDir * strandR / norm(strandRelDir)
) strandO + strandRel;
pointCount = (wideRes + 1) * (strandRes + 1);
module theStrand(strandI) {
color(colors[strandI])
polyhedron(
[ for (wideT = [0 : 360/wideRes : 360.01])
each [ for (strandT = [0 : 360/strandRes : 360.01])
point(wideT, strandI, strandT)
]
],
[ for (wideTI = [0 : (strandRes + 1) : pointCount - 1])
each [ for (strandTI = [wideTI : wideTI + strandRes + 1])
each [
[(strandTI + 1) % pointCount, strandTI % pointCount, (strandTI + strandRes + 1) % pointCount],
[(strandTI + strandRes + 1) % pointCount, strandTI % pointCount, (strandTI + strandRes) % pointCount],
]
]
]
);
}
for (strandI = [0 : strands - 1]) {
theStrand(strandI);
}
|