]> git.vpit.fr Git - perl/modules/LaTeX-TikZ.git/blob - lib/LaTeX/TikZ/Formatter.pm
Only declare once each mod, tag-wise
[perl/modules/LaTeX-TikZ.git] / lib / LaTeX / TikZ / Formatter.pm
1 package LaTeX::TikZ::Formatter;
2
3 use strict;
4 use warnings;
5
6 =head1 NAME
7
8 LaTeX::TikZ::Formatter - LaTeX::TikZ formatter object.
9
10 =head1 VERSION
11
12 Version 0.01
13
14 =cut
15
16 our $VERSION = '0.01';
17
18 use Sub::Name ();
19
20 use LaTeX::TikZ::Tools;
21
22 use Any::Moose;
23 use Any::Moose 'Util::TypeConstraints';
24
25 has 'unit' => (
26  is      => 'ro',
27  isa     => enum([ qw/cm pt/ ]),
28  default => 'cm',
29 );
30
31 has 'format' => (
32  is      => 'ro',
33  isa     => 'Str',
34  default => '%s',
35 );
36
37 has 'scale' => (
38  is      => 'ro',
39  isa     => 'Num',
40  default => 1,
41 );
42
43 has 'width' => (
44  is  => 'ro',
45  isa => 'Maybe[Num]',
46 );
47
48 has 'height' => (
49  is  => 'ro',
50  isa => 'Maybe[Num]',
51 );
52
53 has 'origin' => (
54  is     => 'ro',
55  isa    => 'Maybe[LaTeX::TikZ::Point::Autocoerce]',
56  coerce => 1,
57 );
58
59 sub id {
60  my $tikz = shift;
61
62  join $;, map {
63   my $val = $tikz->$_;
64   defined($val) ? "$val" : '(undef)';
65  } qw/unit format scale width height origin/;
66 }
67
68 my $find_mods = do {
69  our %seen;
70
71  my $find_mods_rec;
72  $find_mods_rec = do {
73   no warnings 'recursion';
74
75   Sub::Name::subname('find_mods_rec' => sub {
76    my ($set, $layers, $others) = @_;
77
78    for ($set->mods) {
79     my $tag = $_->tag;
80     next if $seen{$tag}++;
81
82     if ($_->isa('LaTeX::TikZ::Mod::Layer')) {
83      push @$layers, $_;
84     } else {
85      push @$others, $_;
86     }
87    }
88
89    my @subsets = $set->isa('LaTeX::TikZ::Set::Sequence')
90                  ? $set->kids
91                  : $set->isa('LaTeX::TikZ::Set::Path')
92                    ? $set->ops
93                    : ();
94
95    $find_mods_rec->($_, $layers, $others) for @subsets;
96   });
97  };
98
99  Sub::Name::subname('find_mods' => sub {
100   local %seen = ();
101
102   $find_mods_rec->(@_);
103  });
104 };
105
106 sub render {
107  my $tikz = shift;
108
109  my $seq = LaTeX::TikZ::Set::Sequence->new(
110   kids => \@_,
111  );
112
113  my (@layers, @other_mods);
114  $find_mods->($seq, \@layers, \@other_mods);
115
116  my $o = $tikz->origin;
117  $seq  = $seq->translate($o) if defined $o;
118
119  my $w = $tikz->width;
120  my $h = $tikz->height;
121  my $canvas = '';
122  if (defined $w and defined $h) {
123   require LaTeX::TikZ::Set::Rectangle;
124   $seq->clip(LaTeX::TikZ::Set::Rectangle->new(
125    from   => 0,
126    width  => $w,
127    height => $h,
128   ));
129   $_ = $tikz->len($_) for $w, $h;
130   $canvas = ",papersize={$w,$h},body={$w,$h}";
131  }
132
133  my @header = (
134   "\\usepackage[pdftex,hcentering,vcentering$canvas]{geometry}",
135   "\\usepackage{tikz}",
136   "\\usetikzlibrary{patterns}",
137  );
138
139  my @decls;
140  push @decls, LaTeX::TikZ::Mod::Layer->declare(@layers) if  @layers;
141  push @decls, $_->declare($tikz)                        for @other_mods;
142
143  my @content = (
144   "\\begin{tikzpicture}",
145   @{ $seq->draw($tikz) },
146   "\\end{tikzpicture}",
147  );
148
149  return \@header, \@decls, \@content;
150 }
151
152 sub len {
153  my ($tikz, $len) = @_;
154
155  $len = 0 if LaTeX::TikZ::Tools::numeq($len, 0);
156
157  sprintf $tikz->format . $tikz->unit, $len * $tikz->scale;
158 }
159
160 sub angle {
161  my ($tikz, $a) = @_;
162
163  $a = ($a * 180) / CORE::atan2(0, -1);
164  $a += 360 if LaTeX::TikZ::Tools::numcmp($a, 0) < 0;
165
166  require POSIX;
167  sprintf $tikz->format, POSIX::ceil($a);
168 }
169
170 sub label {
171  my ($tikz, $name, $pos) = @_;
172
173  my $scale = sprintf '%0.2f', $tikz->scale / 5;
174
175  "node[scale=$scale,$pos] {\$$name\$}";
176 }
177
178 sub thickness {
179  my ($tikz, $width) = @_;
180
181  # width=1 is 0.4 points for a scale of 2.5
182  0.8 * $width * ($tikz->scale / 5);
183 }
184
185 use LaTeX::TikZ::Interface formatter => sub {
186  shift;
187
188  __PACKAGE__->new(@_);
189 };
190
191 __PACKAGE__->meta->make_immutable;
192
193 =head1 AUTHOR
194
195 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
196
197 You can contact me by mail or on C<irc.perl.org> (vincent).
198
199 =head1 BUGS
200
201 Please report any bugs or feature requests to C<bug-latex-tikz at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=LaTeX-TikZ>.
202 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
203
204 =head1 SUPPORT
205
206 You can find documentation for this module with the perldoc command.
207
208     perldoc LaTeX::TikZ
209
210 =head1 COPYRIGHT & LICENSE
211
212 Copyright 2010 Vincent Pit, all rights reserved.
213
214 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
215
216 =cut
217
218 1; # End of LaTeX::TikZ::Formatter