aboutsummaryrefslogtreecommitdiff
path: root/pride-braid.scad
blob: b25f3e4269e05cc7336689ad576b1cc57924256d (plain)
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);
}