]> git.vpit.fr Git - perl/modules/LaTeX-TikZ.git/blob - lib/LaTeX/TikZ.pm
b035f0068ae6c5047748acd569dfd003cf3050c4
[perl/modules/LaTeX-TikZ.git] / lib / LaTeX / TikZ.pm
1 package LaTeX::TikZ;
2
3 use strict;
4 use warnings;
5
6 =head1 NAME
7
8 LaTeX::TikZ - Perl object model for generating PGF/TikZ code.
9
10 =head1 VERSION
11
12 Version 0.02
13
14 =cut
15
16 our $VERSION = '0.02';
17
18 =head1 SYNOPSIS
19
20     use LaTeX::TikZ;
21
22     # A couple of lines
23     my $hline = Tikz->line(-1 => 1);
24     my $vline = Tikz->line([ 0, -1 ] => [ 0, 1 ]);
25
26     # Paint them in red
27     $_->mod(Tikz->color('red')) for $hline, $vline;
28
29     # An octogon
30     use Math::Complex;
31     my $octo = Tikz->closed_polyline(
32      map Math::Complex->emake(1, ($_ * pi)/4), 0 .. 7
33     );
34
35     # Only keep a portion of it
36     $octo->clip(Tikz->rectangle(-0.5*(1+i), 2*(1+i)));
37
38     # Fill it with dots
39     $octo->mod(Tikz->pattern(class => 'Dots'));
40
41     # Create a formatter object
42     my $tikz = Tikz->formatter(scale => 5);
43
44     # Put those objects all together and print them
45     my $seq = Tikz->seq($octo, $hline, $vline);
46     my ($head, $decl, $body) = $tikz->render($seq);
47     print "$_\n" for map @$_, $head, $decl, $body;
48
49 =head1 DESCRIPTION
50
51 This module provides an object model for TikZ, a graphical toolkit for LaTeX.
52 It allows you to build structures representing geometrical figures, apply a wide set of modifiers on them, transform them globally with functors, and print them in the context of an existing TeX document.
53
54 =head1 CONCEPTS
55
56 Traditionally, in TikZ, there are two ways of grouping paths together :
57
58 =over 4
59
60 =item *
61
62 either as a I<sequence>, where each path is drawn in its own line :
63
64     \draw (0cm,0cm) -- (0cm,1cm) ;
65     \draw (0cm,0cm) -- (1cm,0cm) ;
66
67 =item *
68
69 or as an I<union>, where paths are all drawn as one line :
70
71     \draw (0cm,0cm) -- (0cm,1cm) (0cm,0cm) -- (1cm,0cm) ;
72
73 =back
74
75 This distinction is important because there are some primitives that only apply to paths but not to sequences, and vice versa.
76
77 Figures are made of path or sequence I<sets> assembled together in a tree.
78
79 I<Modifiers> can be applied onto any set to alter the way in which it is generated.
80 The two TikZ concepts of I<clips> and I<layers> have been unified with the modifiers.
81
82 =head1 INTERFACE
83
84 =head2 Containers
85
86 =head3 C<< Tikz->union(@seq) >>
87
88 Creates a L<LaTeX::TikZ::Set::Union> object out of the paths C<@kids>.
89
90     # A path made of two circles
91     Tikz->union(
92            Tikz->circle(0, 1),
93            Tikz->circle(1, 1),
94           )
95         ->mod(
96            Tikz->fill('red'),
97            'even odd rule',
98           );
99
100 =head3 C<< Tikz->join($connector, @kids) >>
101
102 Creates a L<LaTeX::TikZ::Set::Chain> object that joins the paths C<@kinds> with the given C<$connector> which can be, according to L<LaTeX::TikZ::Set::Chain/connector>, a string, an array reference or a code reference.
103
104     # A stair
105     Tikz->join('-|', map [ $_, $_ ], 0 .. 5);
106
107 =head3 C<< Tikz->chain($kid0, $link0, $kid1, $link1, ... $kidn) >>
108
109 Creates a L<LaTeX::TikZ::Set::Chain> object that chains C<$kid0> to C<$kid1> with the string C<$link0>, C<$kid1> to C<$kid2> with C<$link1>, and so on.
110
111     # An heart-like shape
112     Tikz->chain([ 0, 1 ]
113      => '.. controls (-1, 1.5)    and (-0.75, 0.25) ..' => [ 0, 0 ]
114      => '.. controls (0.75, 0.25) and (1, 1.5)      ..' => [ 0, 1 ]
115     );
116
117 =head3 C<< Tikz->seq(@kids) >>
118
119 Creates a L<LaTeX::TikZ::Set::Sequence> object out of the sequences or paths C<@kids>.
120
121     my $bag = Tikz->seq($sequence, $path, $circle, $raw, $point);
122
123 =head2 Elements
124
125 Those are the building blocks of your geometrical figure.
126
127 =head3 C<< Tikz->point($point) >>
128
129 Creates a L<LaTeX::TikZ::Set::Point> object by coercing C<$point> into a L<LaTeX::TikZ::Point>.
130 The following rules are available :
131
132 =over 4
133
134 =item *
135
136 If C<$point> isn't given, the point defaults to C<(0, 0)>.
137
138     my $origin = Tikz->point;
139
140 =item *
141
142 If C<$point> is a numish Perl scalar, it is treated as C<($point, 0)>.
143
144     my $unit = Tikz->point(1);
145
146 =item *
147
148 If two numish scalars C<$x> and C<$y> are given, they result in the point C<($x, $y)>.
149
150     my $one_plus_i = Tikz->point(1, 1);
151
152 =item *
153
154 If C<$point> is an array reference, it is parsed as C<< ($point->[0], $point->[1]) >>.
155
156     my $i = Tikz->point([ 0, 1 ]);
157
158 =item *
159
160 If C<$point> is a L<Math::Complex> object, the L<LaTeX::TikZ::Point::Math::Complex>  class is automatically loaded and the point is coerced into C<< ($point->Re, $point->Im) >>.
161
162     my $j = Tikz->point(Math::Complex->emake(1, 2*pi/3));
163
164 =back
165
166 You can define automatic coercions from your user point types to L<LaTeX::TikZ::Point> by writing your own C<LaTeX::TikZ::Point::My::User::Point> class.
167 See L<LaTeX::TikZ::Meta::TypeConstraint::Autocoerce> for the rationale and L<LaTeX::TikZ::Point::Math::Complex> for an example.
168
169 =head3 C<< Tikz->line($from => $to) >>
170
171 Creates a L<LaTeX::TikZ::Set::Line> object between the points C<$from> and C<$to>.
172
173     my $x_axis = Tikz->line(-5 => 5);
174     my $y_axis = Tikz->line([ 0, -5 ] => [ 0, 5 ]);
175
176 =head3 C<< Tikz->polyline(@points) >>
177
178 Creates a L<LaTeX::TikZ::Set::Polyline> object that links the successive elements of C<@points> by segments.
179
180     my $U = Tikz->polyline(
181      Tikz->point(0, 1),
182      Tikz->point(0, 0),
183      Tikz->point(1, 0),
184      Tikz->point(1, 1),
185     );
186
187 =head3 C<< Tikz->closed_polyline(@points) >>
188
189 Creates a L<LaTeX::TikZ::Set::Polyline> object that cycles through successive elements of C<@points>.
190
191     my $diamond = Tikz->closed_polyline(
192      Tikz->point(0, 1),
193      Tikz->point(-1, 0),
194      Tikz->point(0, -2),
195      Tikz->point(1, 0),
196     );
197
198 =head3 C<< Tikz->rectangle($from => $to), Tikz->rectangle($from => { width => $width, height => $height }) >>
199
200 Creates a L<LaTeX::TikZ::Set::Rectangle> object with opposite corners C<$from> and C<$to>, or with anchor point C<$from> and dimensions C<$width> and C<$height>.
201
202     my $square = Tikz->rectangle(
203      Tikz->point,
204      Tikz->point(2, 1),
205     );
206
207 =head3 C<< Tikz->circle($center, $radius) >>
208
209 Creates a L<LaTeX::TikZ::Set::Circle> object of center C<$center> and radius C<$radius>.
210
211     my $unit_circle = Tikz->circle(0, 1);
212
213 =head3 C<< Tikz->arc($from => $to, $center) >>
214
215 Creates a L<LaTeX::TikZ::Set> structure that represents an arc going from C<$from> to C<$to> with center C<$center>.
216
217     # An arc. The points are automatically coerced into LaTeX::TikZ::Set::Point objects
218     my $quarter = Tikz->arc(
219      [ 1, 0 ] => [ 0, 1 ],
220      [ 0, 0 ]
221     );
222
223 =head3 C<< Tikz->arrow($from => $to), Tikz->arrow($from => dir => $dir) >>
224
225 Creates a L<LaTeX::TikZ::Set> structure that represents an arrow going from C<$from> towards C<$to>, or starting at C<$from> in direction C<$dir>.
226
227     # An horizontal arrow
228     my $arrow = Tikz->arrow(0 => 1);
229
230 =head3 C<< Tikz->raw($content) >>
231
232 Creates a L<LaTeX::TikZ::Set::Raw> object that will instantiate to the raw TikZ code C<$content>.
233
234 =head2 Modifiers
235
236 Modifiers are applied onto sets by calling the C<< ->mod >> method, like in C<< $set->mod($mod) >>.
237 This method returns the C<$set> object, so it can be chained.
238
239 =head3 C<< Tikz->clip($path) >>
240
241 Creates a L<LaTeX::TikZ::Mod::Clip> object that can be used to clip a given sequence by the (closed) path C<$path>.
242
243     my $box = Tikz->clip(
244      Tikz->rectangle(0 => [ 1, 1 ]),
245     );
246
247 Clips can also be directly applied to sets with the C<< ->clip >> method.
248
249     my $set = Tikz->circle(0, 1.5)
250                   ->clip(Tikz->rectangle([-1, -1] => [1, 1]));
251
252 =head3 C<< Tikz->layer($name, above => \@above, below => \@below) >>
253
254 Creates a L<LaTeX::TikZ::Mod::Layer> object with name C<$name> and optional relative positions C<@above> and C<@below>.
255
256     my $layer = Tikz->layer(
257      'top'
258      above => [ 'main' ],
259     );
260
261 The default layer is C<main>.
262
263 Layers are stored into a global hash, so that when you refer to them by their name, you get the existing layer object.
264
265 Layers can also be directly applied to sets with the C<< ->layer >> method.
266
267     my $dots = Tikz->rectangle(0 => [ 1, 1 ])
268                    ->mod(Tikz->pattern(class => 'Dots'))
269                    ->layer('top');
270
271 =head3 C<< Tikz->scale($factor) >>
272
273 Creates a L<LaTeX::TikZ::Mod::Scale> object that scales the sets onto which it apply by the given C<$factor>.
274
275     my $circle_of_radius_2 = Tikz->circle(0 => 1)
276                                  ->mod(Tikz->scale(2));
277
278 =head3 C<< Tikz->width($line_width) >>
279
280 Creates a L<LaTeX::TikZ::Mod::Width> object that sets the line width to C<$line_width> when applied.
281
282     my $thick_arrow = Tikz->arrow(0 => 1)
283                           ->mod(Tikz->width(5));
284
285 =head3 C<< Tikz->color($color) >>
286
287 Creates a L<LaTeX::TikZ::Mod::Color> object that sets the line color to C<$color> (given in the C<xcolor> syntax).
288
289     # Paint the previous $thick_arrow in red.
290     $thick_arrow->mod(Tikz->color('red'));
291
292 =head3 C<< Tikz->fill($color) >>
293
294 Creates a L<LaTeX::TikZ::Mod::Fill> object that fills the interior of a path with the solid color C<$color> (given in the C<xcolor> syntax).
295
296     my $red_box = Tikz->rectangle(0 => { width => 1, height => 1 })
297                       ->mod(Tikz->fill('red'));
298
299 =head3 C<< Tikz->pattern(class => $class, %args) >>
300
301 Creates a L<LaTeX::TikZ::Mod::Pattern> object of class C<$class> and arguments C<%args> that fills the interior of a path with the specified pattern.
302 C<$class> is prepended with C<LaTeX::TikZ::Mod::Pattern> when it doesn't contain C<::>.
303 See L<LaTeX::TikZ::Mod::Pattern::Dots> and L<LaTeX::TikZ::Mod::Pattern::Lines> for two examples of pattern classes.
304
305     my $hatched_circle = Tikz->circle(0 => 1)
306                              ->mod(Tikz->pattern(class => 'Lines'));
307
308 =head3 C<< Tikz->raw_mod($content) >>
309
310 Creates a L<LaTeX::TikZ::Mod::Raw> object that will instantiate to the raw TikZ mod code C<$content>.
311
312     my $homemade_arrow = Tikz->line(0 => 1)
313                              ->mod(Tikz->raw_mod('->')) # or just ->mod('->')
314
315 =head2 Helpers
316
317 =head3 C<< Tikz->formatter(%args) >>
318
319 Creates a L<LaTeX::TikZ::Formatter> object that can render a L<LaTeX::TikZ::Set> tree.
320
321     my $tikz = Tikz->formatter;
322     my ($header, $declarations, $seq1_body, $seq2_body) = $tikz->render($set1, $set2);
323
324 =head3 C<< Tikz->functor(@rules) >>
325
326 Creates a L<LaTeX::TikZ::Functor> anonymous subroutine that can be called against L<LaTeX::TikZ::Set> trees to clone them according to the given rules.
327 C<@rules> should be a list of array references whose first element is the class/role to match against and the second the handler to execute.
328
329     # The default is a clone method
330     my $clone = Tikz->functor;
331     my $dup = $set->$clone;
332
333     # A translator
334     my $translate = Tikz->functor(
335      'LaTeX::TikZ::Set::Point' => sub {
336       my ($functor, $set, $x, $y) = @_;
337
338       $set->new(
339        point => [
340         $set->x + $x,
341         $set->y + $y,
342        ],
343        label => $set->label,
344        pos   => $set->pos,
345       );
346      },
347     );
348     my $shifted = $set->$translate(1, 1);
349
350     # A mod stripper
351     my $strip = Tikz->functor(
352      '+LaTeX::TikZ::Mod' => sub { return },
353     );
354     my $naked = $set->$strip;
355
356 =cut
357
358 use LaTeX::TikZ::Interface;
359
360 sub import {
361  shift;
362
363  my %args = @_;
364  my $name = $args{as};
365  $name = 'Tikz' unless defined $name;
366  unless ($name =~ /^[a-z_][a-z0-9_]*$/i) {
367   require Carp;
368   Carp::confess('Invalid name');
369  }
370
371  my $pkg   = caller;
372  my $const = sub () { 'LaTeX::TikZ::Interface' };
373  {
374   no strict 'refs';
375   *{$pkg . '::' . $name} = $const;
376  }
377
378  LaTeX::TikZ::Interface->load;
379
380  return;
381 }
382
383 =head1 DEPENDENCIES
384
385 L<Any::Moose> with L<Mouse> 0.80 or greater.
386
387 L<Sub::Name>.
388
389 L<Math::Complex>, L<Math::Trig>.
390
391 L<Scalar::Util>, L<List::Util>, L<Task::Weaken>.
392
393 =head1 SEE ALSO
394
395 PGF/TikZ - L<http://pgf.sourceforge.net>.
396
397 =head1 AUTHOR
398
399 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
400
401 You can contact me by mail or on C<irc.perl.org> (vincent).
402
403 =head1 BUGS
404
405 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>.
406 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
407
408 =head1 SUPPORT
409
410 You can find documentation for this module with the perldoc command.
411
412     perldoc LaTeX::TikZ
413
414 =head1 COPYRIGHT & LICENSE
415
416 Copyright 2010 Vincent Pit, all rights reserved.
417
418 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
419
420 =cut
421
422 1; # End of LaTeX::TikZ