]> git.vpit.fr Git - perl/modules/LaTeX-TikZ.git/blob - lib/LaTeX/TikZ.pm
274c9ae65a7a98206436324b429e30f41fd3ffd3
[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.03
13
14 =cut
15
16 our $VERSION = '0.03';
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<union>
87
88     Tikz->union(@kids)
89
90 Creates a L<LaTeX::TikZ::Set::Union> object out of the paths C<@kids>.
91
92     # A path made of two circles
93     Tikz->union(
94            Tikz->circle(0, 1),
95            Tikz->circle(1, 1),
96           )
97         ->mod(
98            Tikz->fill('red'),
99            'even odd rule',
100           );
101
102 =head3 C<path>
103
104     Tikz->path(@kids)
105
106 A synonym for L</union>.
107
108 =head3 C<join>
109
110     Tikz->join($connector, @kids)
111
112 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.
113
114     # A stair
115     Tikz->join('-|', map [ $_, $_ ], 0 .. 5);
116
117 =head3 C<chain>
118
119     Tikz->chain($kid0, $link0, $kid1, $link1, ... $kidn)
120
121 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.
122
123     # An heart-like shape
124     Tikz->chain([ 0, 1 ]
125      => '.. controls (-1, 1.5)    and (-0.75, 0.25) ..' => [ 0, 0 ]
126      => '.. controls (0.75, 0.25) and (1, 1.5)      ..' => [ 0, 1 ]
127     );
128
129 =head3 C<seq>
130
131     Tikz->seq(@kids)
132
133 Creates a L<LaTeX::TikZ::Set::Sequence> object out of the sequences or paths C<@kids>.
134
135     my $bag = Tikz->seq($sequence, $path, $circle, $raw, $point);
136
137 =head2 Elements
138
139 Those are the building blocks of your geometrical figure.
140
141 =head3 C<point>
142
143     Tikz->point($point)
144
145 Creates a L<LaTeX::TikZ::Set::Point> object by coercing C<$point> into a L<LaTeX::TikZ::Point>.
146 The following rules are available :
147
148 =over 4
149
150 =item *
151
152 If C<$point> isn't given, the point defaults to C<(0, 0)>.
153
154     my $origin = Tikz->point;
155
156 =item *
157
158 If C<$point> is a numish Perl scalar, it is treated as C<($point, 0)>.
159
160     my $unit = Tikz->point(1);
161
162 =item *
163
164 If two numish scalars C<$x> and C<$y> are given, they result in the point C<($x, $y)>.
165
166     my $one_plus_i = Tikz->point(1, 1);
167
168 =item *
169
170 If C<$point> is an array reference, it is parsed as C<< ($point->[0], $point->[1]) >>.
171
172     my $i = Tikz->point([ 0, 1 ]);
173
174 =item *
175
176 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) >>.
177
178     my $j = Tikz->point(Math::Complex->emake(1, 2*pi/3));
179
180 =back
181
182 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.
183 See L<LaTeX::TikZ::Meta::TypeConstraint::Autocoerce> for the rationale and L<LaTeX::TikZ::Point::Math::Complex> for an example.
184
185 =head3 C<line>
186
187     Tikz->line($from => $to)
188
189 Creates a L<LaTeX::TikZ::Set::Line> object between the points C<$from> and C<$to>.
190
191     my $x_axis = Tikz->line(-5 => 5);
192     my $y_axis = Tikz->line([ 0, -5 ] => [ 0, 5 ]);
193
194 =head3 C<polyline>
195
196     Tikz->polyline(@points)
197
198 Creates a L<LaTeX::TikZ::Set::Polyline> object that links the successive elements of C<@points> by segments.
199
200     my $U = Tikz->polyline(
201      Tikz->point(0, 1),
202      Tikz->point(0, 0),
203      Tikz->point(1, 0),
204      Tikz->point(1, 1),
205     );
206
207 =head3 C<closed_polyline>
208
209     Tikz->closed_polyline(@points)
210
211 Creates a L<LaTeX::TikZ::Set::Polyline> object that cycles through successive elements of C<@points>.
212
213     my $diamond = Tikz->closed_polyline(
214      Tikz->point(0, 1),
215      Tikz->point(-1, 0),
216      Tikz->point(0, -2),
217      Tikz->point(1, 0),
218     );
219
220 =head3 C<rectangle>
221
222     Tikz->rectangle($from => $to)
223     Tikz->rectangle($from => { width => $width, height => $height })
224
225 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>.
226
227     my $square = Tikz->rectangle(
228      Tikz->point,
229      Tikz->point(2, 1),
230     );
231
232 =head3 C<circle>
233
234     Tikz->circle($center, $radius)
235
236 Creates a L<LaTeX::TikZ::Set::Circle> object of center C<$center> and radius C<$radius>.
237
238     my $unit_circle = Tikz->circle(0, 1);
239
240 =head3 C<arc>
241
242     Tikz->arc($from => $to, $center)
243
244 Creates a L<LaTeX::TikZ::Set> structure that represents an arc going from C<$from> to C<$to> with center C<$center>.
245
246     # An arc. The points are automatically coerced into LaTeX::TikZ::Set::Point objects
247     my $quarter = Tikz->arc(
248      [ 1, 0 ] => [ 0, 1 ],
249      [ 0, 0 ]
250     );
251
252 =head3 C<arrow>
253
254     Tikz->arrow($from => $to)
255     Tikz->arrow($from => dir => $dir)
256
257 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>.
258
259     # An horizontal arrow
260     my $arrow = Tikz->arrow(0 => 1);
261
262 =head3 C<raw>
263
264     Tikz->raw($content)
265
266 Creates a L<LaTeX::TikZ::Set::Raw> object that will instantiate to the raw TikZ code C<$content>.
267
268 =head2 Modifiers
269
270 Modifiers are applied onto sets by calling the C<< ->mod >> method, like in C<< $set->mod($mod) >>.
271 This method returns the C<$set> object, so it can be chained.
272
273 =head3 C<clip>
274
275     Tikz->clip($path)
276
277 Creates a L<LaTeX::TikZ::Mod::Clip> object that can be used to clip a given sequence by the (closed) path C<$path>.
278
279     my $box = Tikz->clip(
280      Tikz->rectangle(0 => [ 1, 1 ]),
281     );
282
283 Clips can also be directly applied to sets with the C<< ->clip >> method.
284
285     my $set = Tikz->circle(0, 1.5)
286                   ->clip(Tikz->rectangle([-1, -1] => [1, 1]));
287
288 =head3 C<layer>
289
290     Tikz->layer($name, above => \@above, below => \@below)
291
292 Creates a L<LaTeX::TikZ::Mod::Layer> object with name C<$name> and optional relative positions C<@above> and C<@below>.
293
294     my $layer = Tikz->layer(
295      'top'
296      above => [ 'main' ],
297     );
298
299 The default layer is C<main>.
300
301 Layers are stored into a global hash, so that when you refer to them by their name, you get the existing layer object.
302
303 Layers can also be directly applied to sets with the C<< ->layer >> method.
304
305     my $dots = Tikz->rectangle(0 => [ 1, 1 ])
306                    ->mod(Tikz->pattern(class => 'Dots'))
307                    ->layer('top');
308
309 =head3 C<scale>
310
311     Tikz->scale($factor)
312
313 Creates a L<LaTeX::TikZ::Mod::Scale> object that scales the sets onto which it apply by the given C<$factor>.
314
315     my $circle_of_radius_2 = Tikz->circle(0 => 1)
316                                  ->mod(Tikz->scale(2));
317
318 =head3 C<width>
319
320     Tikz->width($line_width)
321
322 Creates a L<LaTeX::TikZ::Mod::Width> object that sets the line width to C<$line_width> when applied.
323
324     my $thick_arrow = Tikz->arrow(0 => 1)
325                           ->mod(Tikz->width(5));
326
327 =head3 C<color>
328
329     Tikz->color($color)
330
331 Creates a L<LaTeX::TikZ::Mod::Color> object that sets the line color to C<$color> (given in the C<xcolor> syntax).
332
333     # Paint the previous $thick_arrow in red.
334     $thick_arrow->mod(Tikz->color('red'));
335
336 =head3 C<fill>
337
338     Tikz->fill($color)
339
340 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).
341
342     my $red_box = Tikz->rectangle(0 => { width => 1, height => 1 })
343                       ->mod(Tikz->fill('red'));
344
345 =head3 C<pattern>
346
347     Tikz->pattern(class => $class, %args)
348
349 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.
350 C<$class> is prepended with C<LaTeX::TikZ::Mod::Pattern> when it doesn't contain C<::>.
351 See L<LaTeX::TikZ::Mod::Pattern::Dots> and L<LaTeX::TikZ::Mod::Pattern::Lines> for two examples of pattern classes.
352
353     my $hatched_circle = Tikz->circle(0 => 1)
354                              ->mod(Tikz->pattern(class => 'Lines'));
355
356 =head3 C<raw_mod>
357
358     Tikz->raw_mod($content)
359
360 Creates a L<LaTeX::TikZ::Mod::Raw> object that will instantiate to the raw TikZ mod code C<$content>.
361
362     my $homemade_arrow = Tikz->line(0 => 1)
363                              ->mod(Tikz->raw_mod('->')) # or just ->mod('->')
364
365 =head2 Helpers
366
367 =head3 C<formatter>
368
369     Tikz->formatter(%args)
370
371 Creates a L<LaTeX::TikZ::Formatter> object that can render a L<LaTeX::TikZ::Set> tree.
372
373     my $tikz = Tikz->formatter;
374     my ($header, $declarations, $seq1_body, $seq2_body) = $tikz->render($set1, $set2);
375
376 =head3 C<functor>
377
378     Tikz->functor(@rules)
379
380 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.
381 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.
382
383     # The default is a clone method
384     my $clone = Tikz->functor;
385     my $dup = $set->$clone;
386
387     # A translator
388     my $translate = Tikz->functor(
389      'LaTeX::TikZ::Set::Point' => sub {
390       my ($functor, $set, $x, $y) = @_;
391
392       $set->new(
393        point => [
394         $set->x + $x,
395         $set->y + $y,
396        ],
397        label => $set->label,
398        pos   => $set->pos,
399       );
400      },
401     );
402     my $shifted = $set->$translate(1, 1);
403
404     # A mod stripper
405     my $strip = Tikz->functor(
406      '+LaTeX::TikZ::Mod' => sub { return },
407     );
408     my $naked = $set->$strip;
409
410 =cut
411
412 use LaTeX::TikZ::Interface;
413
414 sub import {
415  shift;
416
417  my %args = @_;
418  my $name = $args{as};
419  $name = 'Tikz' unless defined $name;
420  unless ($name =~ /^[a-z_][a-z0-9_]*$/i) {
421   require Carp;
422   Carp::confess('Invalid name');
423  }
424
425  my $pkg   = caller;
426  my $const = sub () { 'LaTeX::TikZ::Interface' };
427  {
428   no strict 'refs';
429   *{$pkg . '::' . $name} = $const;
430  }
431
432  LaTeX::TikZ::Interface->load;
433
434  return;
435 }
436
437 =head1 DEPENDENCIES
438
439 L<Mouse> 0.80 or greater.
440
441 L<Sub::Name>.
442
443 L<Math::Complex>, L<Math::Trig>.
444
445 L<Scalar::Util>, L<List::Util>, L<Task::Weaken>.
446
447 =head1 SEE ALSO
448
449 PGF/TikZ - L<http://pgf.sourceforge.net>.
450
451 =head1 AUTHOR
452
453 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
454
455 You can contact me by mail or on C<irc.perl.org> (vincent).
456
457 =head1 BUGS
458
459 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>.
460 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
461
462 =head1 SUPPORT
463
464 You can find documentation for this module with the perldoc command.
465
466     perldoc LaTeX::TikZ
467
468 =head1 COPYRIGHT & LICENSE
469
470 Copyright 2010,2011,2012,2013,2014,2015 Vincent Pit, all rights reserved.
471
472 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
473
474 =cut
475
476 1; # End of LaTeX::TikZ