openjscad-aurora-webapp

Форк
0
/
celtic-knot-ring.jscad 
324 строки · 9.7 Кб
1
// title: Celtic Knot Ring
2
// author: Joost Nieuwenhuijse
3
// license: MIT License
4
// tags: Catmull Spline
5

6
// -*- mode: javascript; -*-
7

8

9
'use strict';
10

11
function getParameterDefinitions() {
12
  return [
13
    {
14
      name: 'hisorhers', 
15
      type: 'choice',
16
      caption: 'For Daniel or Zette:',
17
      values: [0, 1],
18
      captions: ["Dan", "Suzette"], 
19
      initial: 0
20
    }
21
   ];
22
}
23

24

25
var his = true;
26

27

28
var debugcount = 10;
29
function debugprint () {
30
    if (debugcount-- > 0) {
31
    try {
32
        console.log(arguments);
33
    } catch (err) {
34
        //
35
    }
36
    }
37
}
38

39

40
// interpolate between v2 and v3, at time u
41
function catmullRom(v1, v2, v3, v4, u) {
42
    var c1x,c2x,c3x,c4x, resX;
43
    var c1y,c2y,c3y,c4y, resY;
44
    var c1z,c2z,c3z,c4z, resZ;
45

46
    // Coefficients for Matrix M
47
    // these should all be const, but MSIE doens't handle that
48
    var M11 = 0.0;
49
    var M12 = 1.0;
50
    var M13 = 0.0;
51
    var M14 = 0.0;
52
    var M21 =-0.5;
53
    var M22 = 0.0;
54
    var M23 = 0.5;
55
    var M24 = 0.0;
56
    var M31 = 1.0;
57
    var M32 =-2.5;
58
    var M33 = 2.0;
59
    var M34 =-0.5;
60
    var M41 =-0.5;
61
    var M42 = 1.5;
62
    var M43 =-1.5;
63
    var M44 = 0.5;
64
    
65
    c1x =            M12*v2.x;
66
    c2x = M21*v1.x            + M23*v3.x;
67
    c3x = M31*v1.x + M32*v2.x + M33*v3.x + M34*v4.x;
68
    c4x = M41*v1.x + M42*v2.x + M43*v3.x + M44*v4.x;
69
    
70
    c1y =            M12*v2.y;
71
    c2y = M21*v1.y            + M23*v3.y;
72
    c3y = M31*v1.y + M32*v2.y + M33*v3.y + M34*v4.y;
73
    c4y = M41*v1.y + M42*v2.y + M43*v3.y + M44*v4.y;
74
    
75
    c1z =            M12*v2.z;
76
    c2z = M21*v1.z            + M23*v3.z;
77
    c3z = M31*v1.z + M32*v2.z + M33*v3.z + M34*v4.z;
78
    c4z = M41*v1.z + M42*v2.z + M43*v3.z + M44*v4.z;
79
    
80
    resX = (((c4x*u + c3x)*u +c2x)*u + c1x);
81
    resY = (((c4y*u + c3y)*u +c2y)*u + c1y);
82
    resZ = (((c4z*u + c3z)*u +c2z)*u + c1z);
83
    
84
    return new CSG.Vector3D(resX, resY, resZ);
85
}
86

87
var tiny = 0.0000001;
88

89
function catmullRomWithTangent(v1, v2, v3, v4, u) {
90
    var res1, res2, tangent;
91
    if ((u+tiny) <= 1) {
92
    res1 = catmullRom(v1, v2, v3, v4, u) ;
93
    res2 = catmullRom(v1, v2, v3, v4, u+tiny) ;
94
    tangent = res2.minus(res1).unit();
95
    return [res1, tangent];
96
    } else {
97
    res1 = catmullRom(v1, v2, v3, v4, u-tiny) ;
98
    res2 = catmullRom(v1, v2, v3, v4, u) ;
99
    tangent = res2.minus(res1).unit();
100
    return [res2, tangent];
101
    }
102
}
103

104

105

106
// create a CSG by dragging a CAG along a Catmull-Rom spline
107
// where the 'top' of the CAG is 'up' and 'sideways' of
108
// the CAG are perpendicular to 'up' and the spline tangent
109

110

111
function splineExtrude(vCP, numInterps, up, 
112
               cag, transform) {
113
    var polygons = [];
114
    var splinePointsAndTangents = [];
115
    // corners is an array of arrays
116

117
    // corners [j] corresponds to the array of all points on the
118
    // spline with the offset of cag.sides[j].vertex0
119
    
120
    // corners[j][i] is the i'th interpolated point on the master
121
    // spline, plus the offset of cag.sides[j].vertex0
122

123
    var corners = [];
124
    var nSides = cag.sides.length;
125

126
    for (i=0; i< nSides; i++) {
127
    corners.push([]);
128
    }
129

130
    if (typeof(transform) != 'function') {
131
    transform = function(e) { return e; };
132
    }
133
    
134
    // fencepost - do the zeroth point of the zeroth segment
135
    splinePointsAndTangents.push(catmullRomWithTangent(vCP[0],vCP[0+1],
136
                               vCP[0+2],vCP[0+3],0));
137
    for (var j = 0; j <= vCP.length-4; j++) {
138
    // don't do the zeroth point, because it's the same as the
139
    // last point of the previous segment
140
    for (var i = 1; i <= numInterps; i++) {
141
        var u = i/numInterps;
142
        splinePointsAndTangents.push(catmullRomWithTangent(vCP[j],vCP[j+1],
143
                                   vCP[j+2],vCP[j+3],u));
144
    }
145
    }
146
    
147

148
    for (var m=0; m < splinePointsAndTangents.length; m++) {
149
    var sideways = up.cross(splinePointsAndTangents[m][1]);
150
    for (var n = 0; n < nSides; n++) {
151
        corners[n].push(transform(splinePointsAndTangents[m][0]
152
                      .plus(sideways.times(cag.sides[n].vertex0.pos.x))
153
                      .plus(up.times(cag.sides[n].vertex0.pos.y))));
154
        
155
        // vertex1 should be the same as vertex0 of the next side,
156
        // so I don't need to handle it here
157
    }
158
    }
159
    var shared = CSG.Polygon.defaultShared;
160
    
161
    var start = 0;
162
    var end = corners[0].length-1;
163
    var nCorners = corners[0].length;
164

165
    
166

167
    //start cap
168
    var startCap = [];
169
    for (var p =nSides-1; p>=0; p--) {
170
    startCap.push(corners[p][start]);
171
    }
172
    polygons.push(CSG.Polygon.createFromPoints(startCap, shared));
173

174
//    polygons.push(CSG.Polygon.createFromPoints([corners4[start],corners3[start],
175
//                        corners2[start],corners1[start]],
176
//                           shared));
177
    for (var q = start; q < end; q++) { 
178

179
    // This is done as triangles, (rather than rectangles) because
180
    // at points on the spline with high curvature, the inside
181
    // corners can become twisted, which messes up the
182
    // renderer. What I don't know is what happens when such a
183
    // file is converted to STL and sent to a 3D printer.  
184

185
    // In the words of Shapeways, it makes the printer cry.
186

187
    for (var r = 0; r < nSides; r++) {
188

189
        polygons.push(CSG.Polygon.createFromPoints([corners[r][q],  corners[(r+1)%nSides][q],
190
                                                corners[r][q+1]],
191
                                shared));
192
        polygons.push(CSG.Polygon.createFromPoints([              corners[(r+1)%nSides][q],
193
                                corners[(r+1)%nSides][q+1],corners[r][q+1]],
194
                               shared));
195
    }
196
    }
197
    var endCap = [];
198
    for (var s =0; s< nSides; s++) {
199
    endCap.push(corners[s][end]);
200
    }
201
    polygons.push(CSG.Polygon.createFromPoints(endCap, shared));
202

203
    return CSG.fromPolygons(polygons);
204
}
205

206

207
var controlPoints = 
208
    [
209
    [0,     0,  1, 1],   //over across the middle
210
    [10,  10, -1, 0],  //under the first cross
211
    [20,  20,  1, 1],   //over the second cross
212
//  [30,  24,  0, 0],   //curving into the corner
213
    [39,  27.25,  0, 1],   // the sharp corner
214
//  [32,  12,  0, 0],
215
    [30,  10, -1, 0],
216
//  [28,  8,   0, 0],  
217
    [20,  3.75,   0, 0],  // bottom of loop under the corner
218
    [10,  10,  1, 1],
219
    [4,   20,  0, 0], // grand curve near the sharp corner (under the long arc)
220
////    [6,   26,  0, 0],
221
//  [8,   28,  0, 0],
222
    [10,  30, -1, 0],
223
    [24,  34,  0, 0],
224
//  [30,  35,  0, 0], // top of the long arc
225
    [40,  34,  0, 0],
226
    [50,  30,  1, 1], // about where the long arc crosses over
227
//  [58,  22,  0, 0], 
228
    [60,  20, -1, 0],
229
    [70,  10,  1, 1],
230
    [75,  5,  0, 0],
231
    [80,  0,  -1, 0]
232
//  [79.9, .1, -1, 0]   // under the middle (2 cycles right)
233
//  [79.95, .05, -1, 0]   // under the middle (2 cycles right)
234
];
235

236
var numberOfPatterns = 11;
237
var circumference = 40 * numberOfPatterns;
238
var radius = circumference / 2 / Math.PI;
239
var targetCircumference = his?54.3:56.3;
240

241

242
function main (params) {
243
    his = (params.hisorhers != 1);
244
    targetCircumference = his?54.3:56.3;
245

246
    var up = new CSG.Vector3D(0,0,1);
247
    var flipCP = controlPoints.slice();
248
    flipCP.reverse();
249
    flipCP = flipCP.map(function(elt) { return ([elt[0]*-1, elt[1]*-1, 
250
                         elt[2],    elt[3]]); });
251
    // delete the repeated 0,0 point;
252
    controlPoints.shift();
253
    controlPoints = flipCP.concat(controlPoints);
254
    if (!his) {
255
    controlPoints = controlPoints.map(function(elt) { 
256
        return ([elt[0], elt[1]*-1, 
257
             elt[2]*-1,    elt[3]]); });
258
    }
259
    var splines = [];
260
    var lastPoint ;
261
    var tripleCP = [];
262
    // one extra cycle before and after
263
    for (var i=-1; i<numberOfPatterns+1; i++) {
264
//    for (var i=-1; i<4+1; i++) {
265
    tripleCP = tripleCP.concat(controlPoints.map(
266
        function(elt) { return ([elt[0]+(i*160), elt[1], 
267
                     elt[2], elt[3]]); }));
268
    // delete final point so it's not duplicated
269
    lastPoint = tripleCP.pop();
270
    }
271
    // put final point back after the last spline
272
    tripleCP.push(lastPoint);
273

274
    // delete all but last two points of the extra cycle 
275
    // ie. the start/end point and the extra control point
276
    for (var t=0; t < controlPoints.length-2; t++) {
277
    tripleCP.pop();
278
    tripleCP.shift();
279
    }
280

281
    debugprint(tripleCP);
282
    var vCP = tripleCP.map(function(e) {
283
    return new CSG.Vector3D(e[0],e[1],e[2]); 
284
    });
285

286
    var shape1 = CAG.fromPoints([[-4,0], 
287
                 [-4,5.0], [-1.5,8.5],  
288
                 [1.55,8.5], [4, 5.0], 
289
                 [4,0]]);
290

291
    // var shape1 = CAG.fromPoints([[-2.75,0], [0,2.75], [2.75,0]]);
292
    splines.push(splineExtrude(vCP, 11, up, shape1, transformVec3DtoRingSpace));
293
//        splines.push(splineExtrude(vCP, 11, up, shape1));
294
    var csg = new CSG();
295
    for (var u=0; u < splines.length; u++) {
296
    csg = csg.union(splines[u]);
297
    }
298

299
    csg = csg.transform(CSG.Matrix4x4.rotationX(90));
300
    csg = csg.scale(targetCircumference/circumference);    
301
    return csg;
302

303
// 7.5 ring size is 17.7 mm diameter 55.7mm circumference
304
// my guess as to my own ring size is 54mm
305

306
// augh! the pass-under bits are 1 pre-scaled unit narrower 
307
// (after scaling, about 1/8 mm, so .4 mm in extra circumference.
308
}
309

310
function transformVec3DtoRingSpace (vec) {
311
    var m = new CSG.Matrix4x4();
312

313
    m = m.multiply(CSG.Matrix4x4.translation([-vec.x, 0, radius]));
314
    m = m.multiply(CSG.Matrix4x4.rotationY(360*(vec.x)/circumference));
315
    var res = vec.transform(m);
316
    return res;
317
}
318

319
// Question: polygons are supposed to be coplanar vertices, but after
320
// being transformed into ring space, are 4 coplanar vertices still
321
// always coplanar?  I'm pretty sure the answer is 'No'.  Does this matter?
322
// I think yes.  So I can generate triangles instead, easily enough.
323
// Excpet the end caps... which for my model are not actually rotated, 
324
// because they are at the origin or exactly 11 loops away.
325

326

327

328

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.