#! /usr/bin/perl =head1 LICENSE Copyright (c) 2011, Peter S. May Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =cut use warnings; use strict; use 5.010; use Carp; use HTML::Entities (); use Math::Trig; my %user_options = ( count => 10, ); ##### # Used when not set by %user_options my %default_options = ( count => 3, # number of pairs size => 1000, # in pixels size_hub => 0.02, # ratio to size of circle size_text => 50, # in pixels offset_text => 25, # in pixels style_a => "fill:white;", style_b => "fill:black;", style_backdrop => "opacity: 0.5; fill: #808080;", style_hub => "opacity: 0.5; fill: #808080;", ); my %opt = %default_options; $opt{$_} = $user_options{$_} for keys %user_options; $opt{half_size} = $opt{size} / 2; # Conversions between circles and other angular units # 1 cir = 2*pi rad = 360 deg sub cir2deg($) { return $_[0] * 360; } sub deg2cir($) { return $_[0] / 360; } sub cir2rad($) { return $_[0] * 2 * pi; } sub rad2cir($) { return $_[0] / (2 * pi); } # Location of angle on a unit circle sub cossincir($) { my $cir = shift; my $rad = cir2rad($cir); return (cos($rad), sin($rad)); } # Remove exponential notation from a number sub fix($) { for(sprintf('%f',$_[0])) { return "0" if $_ == 0; s/0+$//; s/\.$//; return $_; } } my $circles_per_pair = 1 / $opt{count}; my $circles_per_wedge = $circles_per_pair / 2; ($opt{arc_end_x},$opt{arc_end_y}) = cossincir($circles_per_wedge); $opt{degrees_per_pair} = cir2deg($circles_per_pair); $opt{degrees_per_wedge} = cir2deg($circles_per_wedge); $opt{text_x} = $opt{offset_text}; $opt{text_y} = $opt{size} - $opt{offset_text}; # Ensure that style attributes are XML-safe for(qw/style_a style_b style_backdrop style_hub/) { next unless defined $opt{$_}; $opt{$_} = HTML::Entities::encode_numeric($opt{$_}); } # Ensure that numeric figures are in non-exponential form for(qw/count size half_size arc_end_x arc_end_y degrees_per_pair degrees_per_wedge text_x text_y size_text/) { next unless defined $opt{$_}; $opt{$_} = fix($opt{$_}); } print < EOF # Output clones of the first pair as necessary to fill the circle for(1 .. $opt{count} - 1) { my $deg = fix($opt{degrees_per_pair} * $_); print< EOF } print < $opt{count} EOF