papercraft/mobius-maker

192 lines
3.4 KiB
Perl
Executable File

#!/usr/bin/perl
# Generate the mobius segments for a twisting bracelet
# (0,0)
# (1,0)
# (0.5,sqrt(3)/2)
# center is (0.5, sqrt(3)/3)
use warnings;
use strict;
my $sections = 9;
my $thickness = 150;
my $twist = 120.0;
my $radius = [200,0,0];
my $pi = 2*atan2(1,0);
my $h = sqrt(3)/2;
my $pts = [
v3scale($thickness, [-0.5, -$h/3, 0]),
v3scale($thickness, [ 0.0, +$h*2/3, 0]),
v3scale($thickness, [+0.5, -$h/3, 0]),
];
sub rotate2
{
my $x = shift;
my $y = shift;
my $angle_deg = shift;
my $angle = $angle_deg * $pi / 180;
my $s = sin($angle);
my $c = cos($angle);
return (
$x*$c - $y*$s,
$x*$s + $y*$c,
);
}
sub rotate
{
my $p = shift;
my $angle_deg = shift;
my $axis = shift;
my ($x,$y,$z) = @$p;
if ($axis == 2)
{
($x,$y) = rotate2($x, $y, $angle_deg);
} elsif ($axis == 1)
{
($x,$z) = rotate2($x, $z, $angle_deg);
} elsif ($axis == 0)
{
($y,$z) = rotate2($y, $z, $angle_deg);
}
return [$x,$y,$z];
}
sub v3scale
{
my $s = shift;
my $p1 = shift;
return [
$p1->[0]*$s,
$p1->[1]*$s,
$p1->[2]*$s,
];
}
sub v3add
{
my $p1 = shift;
my $p2 = shift;
return [
$p1->[0] + $p2->[0],
$p1->[1] + $p2->[1],
$p1->[2] + $p2->[2],
];
}
sub v3sub
{
my ($v0, $v1) = @_;
return [
$v0->[0] - $v1->[0],
$v0->[1] - $v1->[1],
$v0->[2] - $v1->[2],
];
}
sub v3cross
{
my ($u,$v) = @_;
my $c = [
$u->[1]*$v->[2] - $u->[2]*$v->[1],
$u->[2]*$v->[0] - $u->[0]*$v->[2],
$u->[0]*$v->[1] - $u->[1]*$v->[0],
];
my $mag = 0
+ $c->[0]*$c->[0]
+ $c->[1]*$c->[1]
+ $c->[2]*$c->[2]
;
return v3scale(1.0/sqrt($mag), $c);
}
sub triangle
{
my ($p0, $p1, $p2) = @_;
my $v1 = v3sub($p1, $p0);
my $v2 = v3sub($p2, $p0);
my $n = v3cross($v2, $v1);
my $rc = sprintf <<"", $n->[0], $n->[1], $n->[2];
facet normal %.4f %.4f %.4f
outer loop
$rc .= sprintf <<"", $p0->[0], $p0->[1], $p0->[2];
vertex %.4f %.4f %.4f
$rc .= sprintf <<"", $p1->[0], $p1->[1], $p1->[2];
vertex %.4f %.4f %.4f
$rc .= sprintf <<"", $p2->[0], $p2->[1], $p2->[2];
vertex %.4f %.4f %.4f
$rc .= <<"";
endloop
endfacet
return $rc;
}
sub module
{
my $n = shift;
# Generate the six points for the triangles
my $p00 = rotate($pts->[0], $n*$twist/$sections, 2);
my $p01 = rotate($pts->[1], $n*$twist/$sections, 2);
my $p02 = rotate($pts->[2], $n*$twist/$sections, 2);
my $p10 = rotate($pts->[0], ($n+1)*$twist/$sections, 2);
my $p11 = rotate($pts->[1], ($n+1)*$twist/$sections, 2);
my $p12 = rotate($pts->[2], ($n+1)*$twist/$sections, 2);
# Now offset them by the radius, after flipping
$p00 = v3add($radius, rotate($p00, 90, 0));
$p01 = v3add($radius, rotate($p01, 90, 0));
$p02 = v3add($radius, rotate($p02, 90, 0));
$p10 = v3add($radius, rotate($p10, 90, 0));
$p11 = v3add($radius, rotate($p11, 90, 0));
$p12 = v3add($radius, rotate($p12, 90, 0));
# rotate them to line up with the radials
$p00 = rotate($p00, $n*360.0/$sections, 2);
$p01 = rotate($p01, $n*360.0/$sections, 2);
$p02 = rotate($p02, $n*360.0/$sections, 2);
$p10 = rotate($p10, ($n+1)*360.0/$sections, 2);
$p11 = rotate($p11, ($n+1)*360.0/$sections, 2);
$p12 = rotate($p12, ($n+1)*360.0/$sections, 2);
# And now generate the triangles
return ''
. triangle($p00, $p01, $p11)
. triangle($p01, $p02, $p12)
. triangle($p02, $p00, $p10)
. triangle($p11, $p10, $p00)
. triangle($p12, $p11, $p01)
. triangle($p10, $p12, $p02)
;
}
print "solid OpenSCAD_Model\n";
print module($_) for 1..$sections;
#print module(0);
#print module(2);
print "endsolid OpenSCAD_Model\n";