function tnb_circle() {
let t0 = 0;
let unit_tangent = T(t0);
let unit_normal = N(t0);
let bi_normal = cross(T(t0), N(t0));
let arrows = d3
.create('transform')
.attr('class', 'tnb_circle')
.attr('translation', '0 0 -1');
let [a, b, c] = unit_tangent;
let norm = Math.sqrt(a ** 2 + b ** 2 + c ** 2);
let theta = -Math.acos(b);
let unit_tangent_transform = arrows
.append('transform')
.attr('translation', `${(r * a) / 2} ${(r * b) / 2} ${(r * c) / 2}`)
.attr('rotation', `${-c} 0 ${a} ${theta}`);
let unit_tangent_vector = unit_tangent_transform.append('shape');
unit_tangent_vector
.append('appearance')
.attr('sortKey', 1)
.append('material')
.attr('diffuseColor', '0 0 0');
unit_tangent_vector
.append('cylinder')
.attr('radius', 0.01)
.attr('height', `${r}`)
.attr('subdivision', '32');
let head_length = 0.2;
let unit_tangent_vector_head = arrows
.append('transform')
.attr('rotation', `${-c} 0 ${a} ${theta}`)
.attr(
'translation',
`${(r - head_length / 2) * a} ${(r - head_length / 2) * b}
${(r - head_length / 2) * c}`
)
.append('shape');
unit_tangent_vector_head
.append('appearance')
.attr('sortKey', 1)
.append('material')
.attr('diffuseColor', '0 0 0');
unit_tangent_vector_head
.append('cone')
.attr('bottomRadius', '0.05')
.attr('topRadius', '0')
.attr('height', head_length);
[a, b, c] = unit_normal;
norm = Math.sqrt(a ** 2 + b ** 2 + c ** 2);
theta = -Math.acos(b);
let normal_transform = arrows
.append('transform')
.attr('translation', `0 0 ${r / 2}`)
.attr('rotation', `${-c} 0 ${a} ${theta}`);
let normal_vector = normal_transform.append('shape');
normal_vector
.append('appearance')
.append('material')
.attr('diffuseColor', '0 0 0');
normal_vector
.append('cylinder')
.attr('radius', 0.01)
.attr('height', `${r}`)
.attr('subdivision', '32');
let normal_vector_head = arrows
.append('transform')
.attr('rotation', `${-c} 0 ${a} ${theta}`)
.attr('translation', `0 0 ${r - head_length / 2}`)
.append('shape');
normal_vector_head
.append('appearance')
.append('material')
.attr('diffuseColor', '0 0 0');
normal_vector_head
.append('cone')
.attr('bottomRadius', '0.05')
.attr('topRadius', '0')
.attr('height', head_length);
[a, b, c] = bi_normal;
norm = Math.sqrt(a ** 2 + b ** 2 + c ** 2);
theta = -Math.acos(b);
let bi_normal_transform = arrows
.append('transform')
.attr('translation', `${(r * a) / 2} ${(r * b) / 2} ${(r * c) / 2}`)
.attr('rotation', `${-c} 0 ${a} ${theta}`);
let bi_normal_vector = bi_normal_transform.append('shape');
bi_normal_vector
.append('appearance')
.append('material')
.attr('diffuseColor', '0 0 0');
bi_normal_vector
.append('cylinder')
.attr('radius', 0.01)
.attr('height', `${r}`)
.attr('subdivision', '32');
let bi_normal_vector_head = arrows
.append('transform')
.attr('rotation', `${-c} 0 ${a} ${theta}`)
.attr(
'translation',
`${(r - head_length / 2) * a} ${(r - head_length / 2) * b}
${(r - head_length / 2) * c}`
)
.append('shape');
bi_normal_vector_head
.append('appearance')
.append('material')
.attr('diffuseColor', '0 0 0');
bi_normal_vector_head
.append('cone')
.attr('bottomRadius', '0.05')
.attr('topRadius', '0')
.attr('height', head_length);
let circle_string = '';
let n = 64;
for (let i = 0; i <= n; i++) {
let t = (2 * i * Math.PI) / n;
let x = r * Math.cos(t) * unit_normal[0] + r * Math.sin(t) * bi_normal[0];
let y = r * Math.cos(t) * unit_normal[1] + r * Math.sin(t) * bi_normal[1];
let z = r * Math.cos(t) * unit_normal[2] + r * Math.sin(t) * bi_normal[2];
circle_string = circle_string + x.toString() + ' ';
circle_string = circle_string + y.toString() + ' ';
circle_string = circle_string + z.toString();
if (i < n) {
circle_string = circle_string + ', ';
}
}
let circle = arrows.append('shape');
circle
.append('IndexedLineSet')
.attr('coordIndex', d3.range(circle_string.split(',').length))
.append('Coordinate')
.attr('point', circle_string);
return arrows;
}