#!/usr/bin/perl -w

use strict;
use Math::Trig;
use Math::Vector::Real;
use IO::File;
use Data::Dumper;
use constant tau => pi*2;

my $ellipse = 60 / 2;
my $circle = 3.5 / 2;
my $xscale = 33 / 100;
my $N = 180; # around ellipse
my $M = 80; # around each circle

my $NMdiv = $ENV{'ELECTRONTOKEN_COARSE'} || 1;

$M /= $NMdiv;
$N /= $NMdiv;

print <<END;
// -*- C -*-
// *** AUTOGENERATED - DO NOT EDIT ***
END

print "torusyup = ", ($circle / sqrt(2)), ";\n";

our @ellipse = map {
    my $theta = tau * $_ / $N;
    V( cos($theta) * $ellipse * $xscale, sin($theta) * $ellipse, 0 )
} 0..($N-1);

#print Dumper(\@ellipse);

our @alongs = map {
    my $i = $_;
    $ellipse[ ($i+1) % $N ] - $ellipse[ ($i-1) % $N];
} 0..($N-1);

our @circles = map {
    my $i = $_;
    my $centre = $ellipse[$i];
    my $axis = $alongs[$i]->versor();
    my $rad0 = $axis x V(0,0,1);
    my $rad1 = $rad0 x $axis;
    [ map {
	my $theta = tau * $_ / $M;
	$centre + $circle * ($rad0 * cos($theta) + $rad1 * sin($theta));
    } 0..($M-1) ];
} 0..($N-1);

sub scadvec ($) {
    my ($v) = @_;
    return "[ ".(join ", ", @$v)." ]"
}

sub torusy () {
    print "module Torusy(){ polyhedron(points=[";
    my $ptix = 0;
    my @cirpt;
    foreach my $i (0..$N-1) {
	foreach my $j (0..$M-1) {
	    print "," if $ptix;
	    print "\n";
	    print "    ",(scadvec $circles[$i][$j]);
	    $cirpt[$i][$j] = $ptix++;
	}
    }
    print "\n  ],\n";

    print "  faces=[";
    foreach my $i (0..$N-1) {
	my $i2 = ($i+1) % $N;
	foreach my $j (0..$M-1) {
	    my $j2 = ($j+1) % $M;
	    print "," if $i || $j;
	    print "\n";
	    print "   [ ", (join ", ",
			    $cirpt[ $i  ][ $j  ],
			    $cirpt[ $i  ][ $j2 ],
			    $cirpt[ $i2 ][ $j  ],
			   ), " ],";
	    print "   [ ", (join ", ",
			    $cirpt[ $i  ][ $j2 ],
			    $cirpt[ $i2 ][ $j2 ],
			    $cirpt[ $i2 ][ $j  ],
			   ), " ]";
	}
    }
    print "\n  ]);\n}\n";
}

torusy();


our @distances;
push @distances, 0;
foreach my $i (1..$N) {
    my $dist = $distances[ $i-1 ];
    $dist += abs($ellipse[$i % $N] - $ellipse[$i-1]);
    $distances[$i] = $dist;
}

sub infodistprop ($) {
    my ($distprop) = @_;
    # returns
    #   ( $ellipse_centreline_point,
    #     $along_vector )
    my $dist = $distprop * $distances[$N];
    foreach my $i (0..$N-1) {
	my $prorata =
	    ($dist - $distances[$i]) /
	    ($distances[$i+1] - $distances[$i]);
	next unless 0 <= $prorata && $prorata <= 1;
	print "// infodistprop $distprop => #$i=$ellipse[$i] $prorata $ellipse[$i+1]\n";
	return (
		(1-$prorata) * $ellipse[$i] + ($prorata) * $ellipse[$i+1],
		$alongs[$i],
	       );
    }
    die "$distprop ?";
}

while (<DATA>) { print };

STDOUT->error and die $!;
STDOUT->flush or die $!;

__DATA__
module Token(){
    difference(){
	for (rot=[ 0,120,240 ])
	    rotate([0,0, rot])
	    translate([0,0,torusyup])
	    Torusy();
	translate([-200,-200,-50])
	    cube([400,400,50]);
    }
}
Token();
