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