Source

boxer / boxer

Trammell Hudson 6c95181 





Trammell Hudson 68c64aa 
Trammell Hudson 4960a0b 
Trammell Hudson 68c64aa 


Trammell Hudson 6c95181 


Trammell Hudson 8038c96 
Trammell Hudson 6c95181 

Trammell Hudson d00596b 
Trammell Hudson 55a98b2 
Trammell Hudson d00596b 



Trammell Hudson 55a98b2 
Trammell Hudson 68c64aa 
Trammell Hudson 6c95181 
Trammell Hudson 6bc457e 



Trammell Hudson f2bd903 
Trammell Hudson 6bc457e 

Trammell Hudson d00596b 


Trammell Hudson 68c64aa 
Trammell Hudson 6bc457e 





Trammell Hudson d00596b 


Trammell Hudson f2bd903 
Trammell Hudson 68c64aa 
Trammell Hudson 6bc457e 

Trammell Hudson d00596b 












Trammell Hudson 68c64aa 
Trammell Hudson 6c95181 

Trammell Hudson d00596b 


Trammell Hudson 6c95181 




Trammell Hudson 13af312 
Trammell Hudson 6c95181 

Trammell Hudson d00596b 





























































Trammell Hudson f2bd903 
Trammell Hudson d00596b 












Trammell Hudson f2bd903 
Trammell Hudson d00596b 












Trammell Hudson f2bd903 
Trammell Hudson d00596b 












Trammell Hudson f2bd903 
Trammell Hudson d00596b 



















Trammell Hudson 8714681 
Trammell Hudson d00596b 


Trammell Hudson 8714681 






Trammell Hudson f2bd903 
Trammell Hudson d00596b 











Trammell Hudson 8714681 






Trammell Hudson f2bd903 
Trammell Hudson d00596b 

Trammell Hudson 8714681 
















Trammell Hudson d00596b 


Trammell Hudson 8714681 







Trammell Hudson f2bd903 
Trammell Hudson 8714681 
Trammell Hudson d00596b 











Trammell Hudson 8714681 






Trammell Hudson f2bd903 
Trammell Hudson d00596b 

Trammell Hudson 8714681 















Trammell Hudson d00596b 



Trammell Hudson 8714681 





Trammell Hudson d00596b 




Trammell Hudson 68c64aa 
Trammell Hudson d00596b 

Trammell Hudson 8714681 
Trammell Hudson d00596b 


Trammell Hudson 8714681 
Trammell Hudson d00596b 



Trammell Hudson 8714681 
Trammell Hudson d00596b 


Trammell Hudson 8714681 
Trammell Hudson d00596b 





#!/usr/bin/perl
# Generate SVG files with a specified number of sides and tabs
# to make a self-locking acrylic or wooden laser cut box.
#
# (c) 2012 Trammell Hudson <hudson@osresearch.net>
#
# 5mm bamboo needs a larger kerf -- 0.2?  power 100, speed 4
# 3mm acrylic works well with 6mm fingers, power 100 speed 10
# 6mm acrylic kerf = 0.1 is ok, 0.2 shatters, power 100 speed 4
# Be sure to measure the acrylic -- some of them vary.
#
use warnings;
use strict;
use Math::Trig;
use Getopt::Long qw(:config no_ignore_case);

my $units = "mm"; # mm = 1, inches = 1000 / 25.4
my $thickness = 3;
my $sides = 4;
my $length = 50;
my $width = 30;
my $height = 20;
my $tab_width = 6;
my $kerf = 0.1;
my $spacing;

my $usage = <<"";
Usage: boxer [options] > box.svg
Options:
	-h | -? | --help	This help
	-T | --tab-width N	Tab width in mm
	-t | --thickness N	Material thickness in mm
	-H | --height N		Height of the box, in mm
	-w | --width N		Outside edge length, in mm
	-l | --length N		Outside edge length, in mm for rectangles
	-k | --kerf N		Kerf in mm (typically 0.1)
	-s | --spacing N	Spacing between pieces in mm


GetOptions(
	'h|?|help'		=> sub { print $usage; exit 0 },
	't|thickness=f'		=> \$thickness,
	'H|height=f'		=> \$height,
	'w|width=f'		=> \$width,
	'l|length=f'		=> \$length,
	'k|kerf=f'		=> \$kerf,
	'T|tab-width=f'		=> \$tab_width,
	's|spacing=f'		=> \$spacing,
) or die $usage;

die "tab should be wider than the material thickness\n"
	if $thickness > $tab_width;

my $num_x_tabs = int(($width - $thickness*2) / ($tab_width * 2));
my $num_y_tabs = int(($length - $thickness*2) / ($tab_width * 2));
my $num_z_tabs = int(($height - $thickness*2) / ($tab_width * 2));
die "tab width $tab_width too large for width $width\n"
	if $num_x_tabs == 0;
die "tab width $tab_width too large for length $length\n"
	if $num_y_tabs == 0;
die "tab width $tab_width too large for height $height\n"
	if $num_z_tabs == 0;

$spacing ||= $kerf * 10;

# Compute the height of the interior triangle
#my $interior_angle = 360.0 / $sides;
#my $interior_len = $edge - $thickness * 2;
#my $interior_radius = ($interior_len/2) / tan(deg2rad($interior_angle/2));


print <<"";
<!-- Created with boxer (http://trmm.net/) -->
<svg xmlns="http://www.w3.org/2000/svg">
<g transform="scale(3.543307)"><!-- scale to mm -->


sub make_translate
{
	my ($x,$y) = @_;
	return "translate($x,$y)";
}


sub make_path
{
	my $rc = <<"";
	<path
		stroke		= "#ff0000"
		fill		= "none"
		stroke-width	= "0.1px"
		d		= "M

	for my $pt (@_)
	{
		my ($x,$y) = @$pt;
		$rc .= "$x,$y\n";
	}

	$rc .= <<"";
	"/>

	return $rc;
}


#
# Applies a transform to a list of SVG objects (paths or other groups)
# Returns a SVG group
#
sub make_group
{
	my $transform = shift;

	my $rc = <<"";
	<g
		transform	= "$transform"
	>

	$rc .= join '\n', @_;
	$rc .= <<"";
	</g>

	return $rc;
}


#
# Generate the flat top and bottom pieces.
# Returns a SVG path
#
sub make_top
{
	my $rc;

	my @points;

	# Bottom edge
	push @points, [$thickness, $thickness];
	my $x = $width/2 - $tab_width * ($num_x_tabs - 0.5);
	for my $n (1..$num_x_tabs)
	{
		push @points,
			[$x - $kerf, $thickness],
			[$x - $kerf, 0],
			[$x + $tab_width + $kerf, 0],
			[$x + $tab_width + $kerf, $thickness],
			;
		$x += $tab_width * 2;
	}

	# Right edge
	push @points, [$width - $thickness, $thickness];
	my $y = $length/2 - $tab_width * ($num_y_tabs - 0.5);
	for my $n (1..$num_y_tabs)
	{
		push @points,
			[$width - $thickness, $y - $kerf],
			[$width, $y - $kerf],
			[$width, $y + $tab_width + $kerf],
			[$width - $thickness, $y + $tab_width + $kerf],
			;
		$y += $tab_width * 2;
	}

	# Top edge
	push @points, [$width - $thickness, $length - $thickness];
	$x = $width/2 + $tab_width * ($num_x_tabs - 0.5);
	for my $n (1..$num_x_tabs)
	{
		push @points,
			[$x + $kerf, $length - $thickness],
			[$x + $kerf, $length],
			[$x - $tab_width - $kerf, $length],
			[$x - $tab_width - $kerf, $length - $thickness],
			;
		$x -= $tab_width * 2;
	}

	# Left edge
	push @points, [$thickness, $length - $thickness];
	$y = $length/2 + $tab_width * ($num_y_tabs - 0.5);
	for my $n (1..$num_y_tabs)
	{
		push @points,
			[$thickness, $y + $kerf],
			[0, $y + $kerf],
			[0, $y - $tab_width - $kerf],
			[$thickness, $y - $tab_width - $kerf],
			;
		$y -= $tab_width * 2;
	}

	# Close the path
	push @points, [$thickness, $thickness];

	return make_path(@points);
}


sub make_side
{
	my ($x_dim, $num_x_tabs, $inset) = @_;
	my @points;

	# Bottom edge
	if ($inset)
	{
		push @points, [$thickness, 0];
	} else {
		push @points, [0,0];
	}

	my $x = $x_dim / 2 - $tab_width * ($num_x_tabs - 0.5);
	for my $n (1..$num_x_tabs)
	{
		push @points,
			[$x - $kerf, 0],
			[$x + $kerf, $thickness],
			[$x - $kerf + $tab_width, $thickness],
			[$x + $kerf + $tab_width, 0],
			;
		$x += $tab_width * 2;
	}

	# Height edge
	if ($inset)
	{
		push @points, [$x_dim - $thickness, 0];
	} else {
		push @points, [$x_dim, 0];
	}

	my $z = $height/2 - $tab_width * ($num_z_tabs - 0.5);
	for my $n (1..$num_z_tabs)
	{
		if ($inset)
		{
			push @points,
				[$x_dim - $thickness, $z - $kerf],
				[$x_dim, $z + $kerf],
				[$x_dim, $z + $tab_width - $kerf],
				[$x_dim - $thickness, $z + $tab_width + $kerf],
				;
		} else {
			push @points,
				[$x_dim, $z - $kerf],
				[$x_dim - $thickness, $z + $kerf],
				[$x_dim - $thickness, $z + $tab_width - $kerf],
				[$x_dim, $z + $tab_width + $kerf],
				;
		}

		$z += $tab_width * 2;
	}

	# Top edge
	if ($inset)
	{
		push @points, [$x_dim - $thickness, $height];
	} else {
		push @points, [$x_dim, $height];
	}

	$x = $x_dim / 2 + $tab_width * ($num_x_tabs - 0.5);

	for my $n (1..$num_x_tabs)
	{
		push @points,
			[$x + $kerf, $height],
			[$x - $kerf, $height - $thickness],
			[$x + $kerf - $tab_width, $height - $thickness],
			[$x - $kerf - $tab_width, $height],
			;
		$x -= $tab_width * 2;
	}

	# Height edge
	if ($inset)
	{
		push @points, [$thickness, $height];
	} else {
		push @points, [0, $height];
	}

	$z = $height/2 + $tab_width * ($num_z_tabs - 0.5);
	for my $n (1..$num_z_tabs)
	{
		if ($inset)
		{
			push @points,
				[$thickness, $z + $kerf],
				[0, $z - $kerf],
				[0, $z + $kerf - $tab_width],
				[$thickness, $z - $kerf - $tab_width],
				;
		} else {
			push @points,
				[0, $z + $kerf],
				[$thickness, $z - $kerf],
				[$thickness, $z + $kerf - $tab_width],
				[0, $z - $kerf - $tab_width],
				;
		}
		$z -= $tab_width * 2;
	}

	# Close it back to the bottom
	if ($inset)
	{
		push @points, [$thickness, 0];
	} else {
		push @points, [0, 0];
	}

	return make_path(@points);
}

print make_group("translate(0,0)", make_top());
print make_group("translate(" . ($width+$spacing) .",0)", make_top());
print make_group(
	make_translate(0, $length + $spacing),
	make_side($width, $num_x_tabs, 0)
);
print make_group(
	make_translate($width + $spacing, $length + $spacing),
	make_side($width, $num_x_tabs, 0)
);

print make_group(
	make_translate(0, $length + $height + $spacing * 2),
	make_side($length, $num_y_tabs, 1)
);
print make_group(
	make_translate($length + $spacing, $length + $height + $spacing * 2),
	make_side($length, $num_y_tabs, 1)
);

print <<"";
</g>
</svg>

__END__
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.