X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2FLaTeX-TikZ.git;a=blobdiff_plain;f=lib%2FLaTeX%2FTikZ%2FFormatter.pm;h=426263f16a517c434e7c2920fb58865c39fa99a9;hp=88bda48942b098a085c825d8370758a0ae3c800d;hb=e6c6fbca8df4f8df7bbce2eb98dd260ed51d9141;hpb=e8f0879ade07eed4f58cd52c0771f4e1ecc90b09 diff --git a/lib/LaTeX/TikZ/Formatter.pm b/lib/LaTeX/TikZ/Formatter.pm index 88bda48..426263f 100644 --- a/lib/LaTeX/TikZ/Formatter.pm +++ b/lib/LaTeX/TikZ/Formatter.pm @@ -15,95 +15,193 @@ Version 0.01 our $VERSION = '0.01'; +=head1 DESCRIPTION + +A formatter object turns a L tree into the actual TikZ code, depending on some parameters such as the scale, the unit or the origin. + +=cut + use Sub::Name (); +use LaTeX::TikZ::Point; + +use LaTeX::TikZ::Interface; + use LaTeX::TikZ::Tools; use Any::Moose; use Any::Moose 'Util::TypeConstraints'; +=head1 ATTRIBUTES + +=head2 C + +=cut + has 'unit' => ( is => 'ro', isa => enum([ qw/cm pt/ ]), default => 'cm', ); +=head2 C + +=cut + has 'format' => ( is => 'ro', isa => 'Str', default => '%s', ); +=head2 C + +=cut + has 'scale' => ( - is => 'ro', + is => 'rw', isa => 'Num', default => 1, ); +=head2 C + +=cut + has 'width' => ( - is => 'ro', + is => 'rw', isa => 'Maybe[Num]', ); +=head2 C + +=cut + has 'height' => ( - is => 'ro', + is => 'rw', isa => 'Maybe[Num]', ); +=head2 C + +=cut + has 'origin' => ( - is => 'ro', - does => 'Maybe[LaTeX::TikZ::Point]', + is => 'rw', + isa => 'LaTeX::TikZ::Point::Autocoerce', + coerce => 1, ); -my $lts_tc = LaTeX::TikZ::Tools::type_constraint('LaTeX::TikZ::Set'); +=head1 METHODS -my $find_mods; -$find_mods = do { - no warnings 'recursion'; +=head2 C - Sub::Name::subname('find_mods' => sub { - my ($set, $layers, $others) = @_; +=cut + +sub id { + my $tikz = shift; + + my $origin = $tikz->origin; + if (defined $origin) { + my ($x, $y) = map $origin->$_, qw/x y/; + $origin = "($x;$y)"; + } else { + $origin = "(0;0)"; + } + + join $;, map { + defined() ? "$_" : '(undef)'; + } map($tikz->$_, qw/unit format scale width height/), $origin; +} + +=head2 C + +=cut + +my $find_mods = do { + our %seen; + + my $find_mods_rec; + $find_mods_rec = do { + no warnings 'recursion'; + + Sub::Name::subname('find_mods_rec' => sub { + my ($set, $layers, $others) = @_; - if ($set->isa('LaTeX::TikZ::Set::Mod')) { for ($set->mods) { + my $tag = $_->tag; + next if $seen{$tag}++; + if ($_->isa('LaTeX::TikZ::Mod::Layer')) { push @$layers, $_; } else { push @$others, $_; } } - } - my @subsets = $set->isa('LaTeX::TikZ::Set::Sequence') - ? $set->kids - : $set->isa('LaTeX::TikZ::Set::Path') - ? $set->ops - : (); + my @subsets = $set->isa('LaTeX::TikZ::Set::Sequence') + ? $set->kids + : $set->isa('LaTeX::TikZ::Set::Path') + ? $set->ops + : (); - $find_mods->($_, $layers, $others) for @subsets; - }) + $find_mods_rec->($_, $layers, $others) for @subsets; + }); + }; + + Sub::Name::subname('find_mods' => sub { + local %seen = (); + + $find_mods_rec->(@_); + }); }; -sub render { - my $tikz = shift; +my $translate; - $lts_tc->assert_valid($_) for @_; +sub render { + my ($tikz, @sets) = @_; + + unless ($translate) { + require LaTeX::TikZ::Functor; + $translate = LaTeX::TikZ::Functor->new( + rules => [ + 'LaTeX::TikZ::Set::Point' => sub { + my ($functor, $set, $v) = @_; + + $set->new( + point => [ + $set->x + $v->x, + $set->y + $v->y, + ], + label => $set->label, + pos => $set->pos, + ); + }, + ], + ); + } - my $seq = LaTeX::TikZ::Set::Sequence->new( - kids => \@_, - ); + my $origin = $tikz->origin; + if (defined $origin) { + @sets = map $_->$translate($origin), @sets; + } my (@layers, @other_mods); + my $seq = LaTeX::TikZ::Set::Sequence->new(kids => \@sets); $find_mods->($seq, \@layers, \@other_mods); - my $o = $tikz->origin; - $seq = $seq->translate($o) if defined $o; - my $w = $tikz->width; my $h = $tikz->height; my $canvas = ''; if (defined $w and defined $h) { - $seq->clip(Tikz->rectangle(Tikz->point(0) => [ $w, $h ])); + require LaTeX::TikZ::Set::Rectangle; + for (@sets) { + $_->clip(LaTeX::TikZ::Set::Rectangle->new( + from => 0, + width => $w, + height => $h, + )); + } $_ = $tikz->len($_) for $w, $h; $canvas = ",papersize={$w,$h},body={$w,$h}"; } @@ -115,30 +213,22 @@ sub render { ); my @decls; - if (@layers) { - my $layers_decl = LaTeX::TikZ::Mod::Layer->declare(@layers); - if (defined $layers_decl) { - chomp $layers_decl; - push @decls, $layers_decl; - } - } - for (@other_mods) { - my $decl = $_->declare($tikz); - if (defined $decl) { - chomp $decl; - push @decls, $decl; - } - } + push @decls, LaTeX::TikZ::Mod::Layer->declare(@layers) if @layers; + push @decls, $_->declare($tikz) for @other_mods; - my @content = ( + my @bodies = map [ "\\begin{tikzpicture}", - do { my $s = $seq->draw($tikz); chomp $s; $s }, + @{ $_->draw($tikz) }, "\\end{tikzpicture}", - ); + ], @sets; - return \@header, \@decls, \@content; + return \@header, \@decls, @bodies; } +=head2 C + +=cut + sub len { my ($tikz, $len) = @_; @@ -147,6 +237,10 @@ sub len { sprintf $tikz->format . $tikz->unit, $len * $tikz->scale; } +=head2 C + +=cut + sub angle { my ($tikz, $a) = @_; @@ -157,14 +251,22 @@ sub angle { sprintf $tikz->format, POSIX::ceil($a); } +=head2 C