boxer / boxer

#!/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>
#
use warnings;
use strict;
use Math::Trig;
use Getopt::Long;

my $units = "mm"; # mm = 1, inches = 1000 / 25.4
my $thickness = 6;
my $sides = 4;
my $edge = 95;
my $height = 95;
my $tab_width = 20;
my $kerf = 0.1;

my $usage = <<"";
Usage: boxer [options] > box.svg
Options:
	-h | -? | --help	This help
	-t | --thickness N	Material thickness in mm
	-H | --height N		Height of the box, in mm
	-e | --edge N		Outside edge length, in mm
	-n | --sides N		Number of sides (for polygonal boxes)


GetOptions(
	'h|?|help'		=> sub { print $usage; exit 0 },
	't|thickness=f'		=> \$thickness,
	'H|height=f'		=> \$height,
	'e|edge=f'		=> \$edge,
	'n|sides=i'		=> \$sides,
) or die $usage;


# 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 -->


#
# Draw the top (and bottom piece)
#
print <<"";
<g transform="translate($edge $edge)">

for my $side (0..$sides-1)
{
	my $angle = (360 / $sides) * $side;
	my $hx = $interior_len / 2;

	# Put one tab in the middle
	my $tab_x1 = $edge/2 - $tab_width/2 - $kerf - $thickness/2;
	my $tab_x2 = $edge/2 + $tab_width/2 + $kerf - $thickness/2;

	print <<"";
	<g
		transform="rotate(-$angle) translate(-$hx $interior_radius)"
	><path
		stroke="#ff0000"
		fill="none"
		stroke-width="0.1px"
		d="M

	print <<"";
		0 0
		$tab_x1 0
		$tab_x1 $thickness
		$tab_x2 $thickness
		$tab_x2 0
		$interior_len 0

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

}

print <<"";
</g>

#
# Draw the edge pieces
#
print <<"";
<g transform="translate(0 @{[$edge*2]})">

for my $side (0..$sides-1)
{
	my $origin_x = $side * ($edge + $thickness + 2);

	# Put one tab in the middle of the top and bottom edges
	# Make it smaller than the kerf for a tighter fit with the
	# prodruting tab on the top/bottom pieces
	my $top_tab_x1 = $edge/2 - $tab_width/2 + $kerf - $thickness/2;
	my $top_tab_x2 = $edge/2 + $tab_width/2 - $kerf - $thickness/2;

	my $bottom_tab_x1 = $edge/2 - $tab_width/2 + $kerf + $thickness/2;
	my $bottom_tab_x2 = $edge/2 + $tab_width/2 - $kerf + $thickness/2;

	# Put one tab in the middle of the left edge.  It goes in,
	# so make it smaller than than the kerf.
	my $left_tab_x1 = $height/2 - $tab_width/2 + $kerf;
	my $left_tab_x2 = $height/2 + $tab_width/2 - $kerf;

	# Put one tab in the middle of the right edge.  it goes out,
	# so make it larger than the kerf.
	my $right_tab_x1 = $height/2 - $tab_width/2 - $kerf;
	my $right_tab_x2 = $height/2 + $tab_width/2 + $kerf;

	print <<"";
	<g transform="translate($origin_x 0)">

	print <<"";
	<!-- bottom edge -->
	<path
		transform="translate(0 0) rotate(0 0 0)"
		stroke="#ff0000"
		fill="none"
		stroke-width="0.1px"
		d="M
			$thickness 0
			@{[$bottom_tab_x1-$kerf]} 0
			$bottom_tab_x1 -$thickness
			$bottom_tab_x2 -$thickness
			@{[$bottom_tab_x2+$kerf]} 0
			$edge 0
		"
	/>

	print <<"";
	<!-- right side edge; tab goes out-->
	<path
		transform="translate($edge 0) rotate(-90 0 0)"
		stroke="#ff0000"
		stroke-width="0.1px"
		fill="none"
		d="M
			0 0
			$right_tab_x1 0
			$right_tab_x1 $thickness
			$right_tab_x2 $thickness
			$right_tab_x2 0
			$height 0
		"
	/>

	print <<"";
	<!-- top edge -->
	<path
		transform="translate($edge -$height) rotate(-180 0 0)"
		stroke="#ff0000"
		stroke-width="0.1px"
		fill="none"
		d="M
			0 0
			@{[$top_tab_x1-$kerf]} 0
			$top_tab_x1 -$thickness
			$top_tab_x2 -$thickness
			@{[$top_tab_x2+$kerf]} 0
			@{[$edge - $thickness]} 0
		"
	/>

	print <<"";
	<!-- left side edge; tab goes in-->
	<path
		transform="translate($thickness -$height) rotate(-270 0 0)"
		stroke="#ff0000"
		stroke-width="0.1px"
		fill="none"
		d="M
			0 0
			@{[$left_tab_x1-$kerf]} 0
			$left_tab_x1 -$thickness
			$left_tab_x2 -$thickness
			@{[$left_tab_x2+$kerf]} 0
			$height 0
		"
	/>

	print <<"";
	</g>

}

print <<"";
</g>


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.