#!/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 = 12;
my $thickness = 50;
my $twist = 240.0;
my $radius = [70,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";