our $VERSION = '0.01';
+=head1 SYNOPSIS
+
+ use LaTeX::TikZ;
+
+ # A couple of lines
+ my $hline = Tikz->line(-1 => 1);
+ my $vline = Tikz->line([ 0, -1 ] => [ 0, -1 ]);
+
+ # Paint them in red
+ $_->mod(Tikz->color('red')) for $hline, $vline;
+
+ # An octogon
+ use Math::Complex;
+ my $octo = Tikz->closed_polyline(
+ map Math::Complex->emake(1, ($_ * pi)/4), 0 .. 7
+ );
+
+ # Only keep a portion of it
+ $octo->clip(Tikz->rectangle(-0.5*(1+i), 2*(1+i)));
+
+ # Fill it with dots
+ $octo->mod(Tikz->pattern(class => 'Dots'));
+
+ # Create a formatter object
+ my $tikz = Tikz->formatter;
+
+ # Put those objects all together and print them
+ my $seq = Tikz->seq($octo, $hline, $vline);
+ my ($head, $decl, $body) = $tikz->render($seq);
+ print "$_\n" for map @$_, $head, $decl, $body;
+
+=head1 DESCRIPTION
+
+This module provides an object model for TikZ, a graphical tookit for LaTeX.
+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.
+
+=cut
+
use LaTeX::TikZ::Interface;
sub import {
return;
}
+=head1 SEE ALSO
+
+PGF/TikZ - L<http://pgf.sourceforge.net>.
+
=head1 AUTHOR
Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
our $VERSION = '0.01';
+=head1 DESCRIPTION
+
+A formatter object turns a L<LaTeX::TikZ::Set> 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 Any::Moose;
use Any::Moose 'Util::TypeConstraints';
+=head1 ATTRIBUTES
+
+=head2 C<unit>
+
+=cut
+
has 'unit' => (
is => 'ro',
isa => enum([ qw/cm pt/ ]),
default => 'cm',
);
+=head2 C<format>
+
+=cut
+
has 'format' => (
is => 'ro',
isa => 'Str',
default => '%s',
);
+=head2 C<scale>
+
+=cut
+
has 'scale' => (
is => 'rw',
isa => 'Num',
default => 1,
);
+=head2 C<width>
+
+=cut
+
has 'width' => (
is => 'rw',
isa => 'Maybe[Num]',
);
+=head2 C<height>
+
+=cut
+
has 'height' => (
is => 'rw',
isa => 'Maybe[Num]',
);
+=head2 C<origin>
+
+=cut
+
has 'origin' => (
is => 'rw',
isa => 'LaTeX::TikZ::Point::Autocoerce',
coerce => 1,
);
+=head1 METHODS
+
+=head2 C<id>
+
+=cut
+
sub id {
my $tikz = shift;
} map($tikz->$_, qw/unit format scale width height/), $origin;
}
+=head2 C<render>
+
+=cut
+
my $find_mods = do {
our %seen;
return \@header, \@decls, @bodies;
}
+=head2 C<len>
+
+=cut
+
sub len {
my ($tikz, $len) = @_;
sprintf $tikz->format . $tikz->unit, $len * $tikz->scale;
}
+=head2 C<angle>
+
+=cut
+
sub angle {
my ($tikz, $a) = @_;
sprintf $tikz->format, POSIX::ceil($a);
}
+=head2 C<label>
+
+=cut
+
sub label {
my ($tikz, $name, $pos) = @_;
"node[scale=$scale,$pos] {$name}";
}
+=head2 C<thickness>
+
+=cut
+
sub thickness {
my ($tikz, $width) = @_;
our $VERSION = '0.01';
+=head1 DESCRIPTION
+
+A functor takes a L<LaTeX::TikZ::Set> tree and clones it according to certain rules.
+
+=cut
+
use Carp ();
use Sub::Name ();
});
}
+=head1 METHODS
+
+=head2 C<default_rule>
+
+=cut
+
sub default_rule {
shift;
$insert_rule->($rule, $rule->[2] ? \@default_set_rules : \@default_mod_rules);
}
+=head2 C<< new rules => [ $class_name => sub { ... }, ... ] >>
+
+=cut
+
sub new {
my ($class, %args) = @_;
use Sub::Name ();
+=head1 METHODS
+
+=head2 C<< register $keyword => $code >>
+
+Registers C<$code> to be available with C<< Tikz->$keyword >>.
+
+=cut
+
sub register {
shift;
return;
}
+=head2 C<load>
+
+Load all the modules of the L<LaTeX::TikZ> official suite that register a keyword in the interface.
+
+=cut
+
sub load {
require LaTeX::TikZ::Formatter; # formatter
require LaTeX::TikZ::Functor; # functor
extends any_moose('Meta::TypeConstraint');
+=head1 ATTRIBUTES
+
+=head2 C<mapper>
+
+=cut
+
has 'mapper' => (
is => 'ro',
isa => 'CodeRef',
);
+=head2 C<parent_name>
+
+=cut
+
has 'parent_name' => (
is => 'ro',
isa => 'ClassName',
required => 1,
);
+=head2 C<user_constraint>
+
+=cut
+
has 'user_constraint' => (
is => 'ro',
isa => 'Maybe[CodeRef]',
required => 1,
);
+=head1 METHODS
+
+=cut
+
around 'new' => sub {
my ($orig, $class, %args) = @_;
$tc = $class->$orig(%args);
};
+=head2 C<load>
+
+=cut
+
sub load {
my ($tc, $thing) = @_;
our $VERSION = '0.01';
+=head1 DESCRIPTION
+
+This role should be consumed by all the modifier classes.
+
+=cut
+
use Any::Moose 'Role';
use Any::Moose 'Util::TypeConstraints';
+=head1 METHODS
+
+These methods are required by the interface :
+
+=over 4
+
+=item *
+
+C<tag>
+
+=item *
+
+C<cover>
+
+=item *
+
+C<declare>
+
+=item *
+
+C<apply>
+
+=back
+
+=cut
+
requires qw(
tag
cover
register_type_constraint
/ ];
+=head1 ATTRIBUTES
+
+=head2 C<x>
+
+The abscissa of the point.
+
+=cut
+
has 'x' => (
is => 'ro',
isa => 'Num',
required => 1,
);
+=head2 C<y>
+
+The ordinate of the point.
+
+=cut
+
has 'y' => (
is => 'ro',
isa => 'Num',
use Any::Moose;
+=head1 ATTRIBUTES
+
+=head2 C<mods>
+
+=cut
+
has '_mods' => (
is => 'ro',
isa => 'Maybe[ArrayRef[LaTeX::TikZ::Mod::Formatted]]',
default => sub { +{ } },
);
+=head2 C<body>
+
+=cut
+
has '_body' => (
is => 'rw',
isa => 'LaTeX::TikZ::Scope|ArrayRef[Str]',
my $_body_tc = __PACKAGE__->meta->find_attribute_by_name('_body')
->type_constraint;
+=head1 METHODS
+
+=head2 C<mod>
+
+=cut
+
sub mod {
my $scope = shift;
$scope;
}
+=head2 C<body>
+
+=cut
+
sub body {
my $scope = shift;
'@{}' => 'dereference',
);
+=head2 C<flatten>
+
+=cut
+
sub flatten {
my ($scope) = @_;
return \@left, \@common, \@right;
});
+=head2 C<instantiate>
+
+=cut
+
sub instantiate {
my ($scope) = @_;
return @body;
}
+=head2 C<dereference>
+
+=cut
+
sub dereference { [ $_[0]->instantiate ] }
+=head2 C<fold>
+
+=cut
+
sub fold {
my ($left, $right, $rev) = @_;
use Any::Moose 'Role';
-requires qw(
- draw
-);
+=head1 ATTRIBUTES
+
+=head2 C<mods>
+
+Returns the list of the L<LaTeX::TikZ::Mod> objects associated with the current set.
+
+=cut
has '_mods' => (
is => 'ro',
sub mods { @{$_[0]->_mods} }
+=head1 METHODS
+
+This method is required by the interface :
+
+=over 4
+
+=item *
+
+C<draw>
+
+=back
+
+=cut
+
+requires qw(
+ draw
+);
+
+=head2 C<mod @mods>
+
+Apply the given list of L<LaTeX::TikZ::Mod> objects to the current set.
+
+=cut
+
my $ltm_tc = LaTeX::TikZ::Tools::type_constraint('LaTeX::TikZ::Mod');
my $ltml_tc = LaTeX::TikZ::Tools::type_constraint('LaTeX::TikZ::Mod::Layer');
my $ltmc_tc = LaTeX::TikZ::Tools::type_constraint('LaTeX::TikZ::Mod::Clip');
};
}
+=head2 C<layer $layer>
+
+Puts the current set in the corresponding layer.
+This is a shortcut for C<< $set->mod(Tikz->layer($layer)) >>.
+
+=cut
+
sub layer {
return $_[0] unless @_ > 1;
)
}
+=head2 C<clip $path>
+
+Clips the current set by the path given by C<$path>.
+This is a shortcut for C<< $set->mod(Tikz->clip($path)) >>.
+
+=cut
+
sub clip {
return $_[0] unless @_ > 1;
use Any::Moose;
use Any::Moose 'Util::TypeConstraints';
+=head1 RELATIONSHIPS
+
+This class consumes the L<LaTeX::TikZ::Set::Op> role, and as such implements the L</path> method.
+
+=cut
+
with 'LaTeX::TikZ::Set::Op';
+=head1 ATTRIBUTES
+
+=head2 C<center>
+
+A L<LaTeX::TikZ::Set::Point> object describing the center of the circle.
+
+=cut
+
has 'center' => (
is => 'ro',
isa => 'LaTeX::TikZ::Set::Point',
coerce => 1,
);
+=head2 C<radius>
+
+The radius of the circle as a non-negative real number.
+
+=cut
+
has 'radius' => (
is => 'ro',
isa => subtype('Num' => where { LaTeX::TikZ::Tools::numcmp($_, 0) > 0 }),
required => 1,
);
+=head1 METHODS
+
+=head2 C<path>
+
+=cut
+
sub path {
my $set = shift;
my $tikz = $_[0];
use Any::Moose;
+=head1 RELATIONSHIPS
+
+This class consumes the L<LaTeX::TikZ::Set::Op> role, and as such implements the L</path> method.
+
+=cut
+
with 'LaTeX::TikZ::Set::Op';
+=head1 ATTRIBUTES
+
+=head2 C<from>
+
+The first endpoint of the line, as a L<LaTeX::TikZ::Set::Point> object.
+
+=cut
+
has 'from' => (
is => 'ro',
isa => 'LaTeX::TikZ::Set::Point',
coerce => 1,
);
+=head2 C<to>
+
+The second endpoint of the line, also as a L<LaTeX::TikZ::Set::Point> object.
+
+=cut
+
has 'to' => (
is => 'ro',
isa => 'LaTeX::TikZ::Set::Point',
coerce => 1,
);
+=head1 METHODS
+
+=head2 C<path>
+
+=cut
+
sub path {
my $set = shift;
Version 0.01
+=head1 DESCRIPTION
+
+L<LaTeX::TikZ::Set> objects that are mutable consume this role.
+This forces them to implement an C<add> method describing how more elements can be added to the set.
+
=cut
our $VERSION = '0.01';
use Any::Moose 'Role';
+=head1 METHODS
+
+This method is required by the interface :
+
+=over 4
+
+=item *
+
+C<add>
+
+=back
+
+=cut
+
requires qw(
add
);
our $VERSION = '0.01';
+=head1 DESCRIPTION
+
+Ops are the components of a path.
+They can be built together to form a path.
+Thus, they are all the elements against which we can call the C<path> method.
+
+=cut
+
use Any::Moose 'Role';
+=head1 RELATIONSHIPS
+
+This role consumes the L<LaTeX::TikZ::Set> role, and as such implements the L</draw> method.
+
+=cut
+
with 'LaTeX::TikZ::Set';
+=head1 METHODS
+
+This method is required by the interface :
+
+=over 4
+
+=item *
+
+C<path>
+
+=back
+
+=cut
+
requires qw(
path
);
+=head2 C<draw>
+
+=cut
+
sub draw {
my $set = shift;
use Any::Moose 'Util::TypeConstraints'
=> [ qw/subtype as where find_type_constraint/ ];
+=head1 RELATIONSHIPS
+
+This class consumes the L<LaTeX::TikZ::Set::Op> and L<LaTeX::TikZ::Set::Mutable> roles, and as such implements the L</path> and L</add> methods.
+
+=cut
+
with qw(
LaTeX::TikZ::Set::Op
LaTeX::TikZ::Set::Mutable
);
+=head1 ATTRIBUTES
+
+=head2 C<ops>
+
+The L<LaTeX::TikZ::Set::Op> objects that from the path.
+
+=cut
+
subtype 'LaTeX::TikZ::Set::Path::Elements'
=> as 'Object'
=> where { $_->does('LaTeX::TikZ::Set::Op') };
sub ops { @{$_[0]->_ops} }
+=head1 METHODS
+
+=head2 C<add>
+
+=cut
+
my $ltspe_tc = find_type_constraint('LaTeX::TikZ::Set::Path::Elements');
sub add {
$set;
}
+=head2 C<path>
+
+=cut
+
sub path {
my $set = shift;
use Any::Moose;
use Any::Moose 'Util::TypeConstraints';
+=head1 RELATIONSHIPS
+
+This class consumes the L<LaTeX::TikZ::Set::Op> role, and as such implements the L</path> method.
+
+=cut
+
with 'LaTeX::TikZ::Set::Op';
+=head1 ATTRIBUTES
+
+=head2 C<point>
+
+The L<LaTeX::TikZ::Point> object representing the underlying geometrical point.
+
+=cut
+
has 'point' => (
is => 'ro',
isa => 'LaTeX::TikZ::Point::Autocoerce',
handles => [ qw/x y/ ],
);
+=head2 C<label>
+
+An optional label for the point.
+
+=cut
+
has 'label' => (
is => 'rw',
isa => 'Maybe[Str]',
default => undef,
);
+=head2 C<pos>
+
+The position of the label around the point.
+
+=cut
+
enum 'LaTeX::TikZ::Set::Point::Positions' => (
'below left',
'below',
=> from 'LaTeX::TikZ::Set::Point'
=> via { $_->point };
+=head1 METHODS
+
+=head2 C<path>
+
+=cut
+
sub path {
my ($set, $tikz) = @_;
=head1 NAME
-LaTeX::TikZ::Set::Polyline - A set object representing a line.
+LaTeX::TikZ::Set::Polyline - A set object representing a possibly closed path composed of contiguous lines.
=head1 VERSION
use Any::Moose;
use Any::Moose 'Util::TypeConstraints';
+=head1 RELATIONSHIPS
+
+This class consumes the L<LaTeX::TikZ::Set::Op> role, and as such implements the L</path> method.
+
+=cut
+
with 'LaTeX::TikZ::Set::Op';
subtype 'LaTeX::TikZ::Set::Polyline::Vertices'
=> from 'ArrayRef[Any]'
=> via { [ map LaTeX::TikZ::Set::Point->new(point => $_), @$_ ] };
+=head1 ATTRIBUTES
+
+=head2 C<points>
+
+The list of the successive vertices of the path.
+
+=cut
+
has '_points' => (
is => 'ro',
isa => 'LaTeX::TikZ::Set::Polyline::Vertices',
sub points { @{$_[0]->_points} }
+=head2 C<closed>
+
+A boolean that indicates whether the path is closed or not.
+
+=cut
+
has 'closed' => (
is => 'ro',
isa => 'Bool',
default => 0,
);
+=head1 METHODS
+
+=head2 C<path>
+
+=cut
+
sub path {
my $set = shift;
use Any::Moose;
+=head1 RELATIONSHIPS
+
+This class consumes the L<LaTeX::TikZ::Set::Op> role, and as such implements the L</path> method.
+
+=cut
+
with 'LaTeX::TikZ::Set::Op';
+=head1 ATTRIBUTES
+
+=head2 C<content>
+
+The bare string the raw mod is made of.
+
+=cut
+
has 'content' => (
is => 'ro',
isa => 'Str',
required => 1,
);
+=head1 METHODS
+
+=head2 C<path>
+
+=cut
+
sub path { $_[0]->content }
LaTeX::TikZ::Interface->register(
use Any::Moose;
+=head1 RELATIONSHIPS
+
+This class consumes the L<LaTeX::TikZ::Set::Op> role, and as such implements the L</path> method.
+
+=cut
+
with 'LaTeX::TikZ::Set::Op';
+=head1 ATTRIBUTES
+
+=head2 C<from>
+
+The first corner of the rectangle, as a L<LaTeX::TikZ::Set::Point> object.
+
+=cut
+
has 'from' => (
is => 'ro',
isa => 'LaTeX::TikZ::Set::Point',
coerce => 1,
);
+=head2 C<to>
+
+The opposite endpoint of the rectangle, also as a L<LaTeX::TikZ::Set::Point> object.
+
+=cut
+
has 'to' => (
is => 'ro',
isa => 'LaTeX::TikZ::Set::Point',
coerce => 1,
);
+=head2 C<width>
+
+The algebraic width of the rectangle.
+
+=cut
+
has 'width' => (
is => 'ro',
isa => 'Num',
);
+=head2 C<height>
+
+The algebraic height of the rectangle.
+
+=cut
+
has 'height' => (
is => 'ro',
isa => 'Num',
);
+=head1 METHODS
+
+=head2 C<path>
+
+=cut
+
sub path {
my $set = shift;
use Any::Moose 'Util::TypeConstraints'
=> [ qw/subtype as where find_type_constraint/ ];
+=head1 RELATIONSHIPS
+
+This class consumes the L<LaTeX::TikZ::Set> and L<LaTeX::TikZ::Set::Mutable> roles, and as such implements the L</draw> and L</add> methods.
+
+=cut
+
with qw(
LaTeX::TikZ::Set
LaTeX::TikZ::Set::Mutable
or $_->isa('LaTeX::TikZ::Set::Sequence')
};
+=head1 ATTRIBUTES
+
+=head2 C<kids>
+
+The L<LaTeX::TikZ::Set::Op> or L<LaTeX::TikZ::Set::Sequence> objects that from the sequence.
+
+=cut
+
has '_kids' => (
is => 'ro',
isa => 'Maybe[ArrayRef[LaTeX::TikZ::Set::Sequence::Elements]]',
sub kids { @{$_[0]->_kids} }
+=head1 METHODS
+
+=head2 C<add>
+
+=cut
+
my $ltsse_tc = find_type_constraint('LaTeX::TikZ::Set::Sequence::Elements');
sub add {
$set;
}
+=head2 C<draw>
+
+=cut
+
sub draw {
my $set = shift;
use Any::Moose 'Util::TypeConstraints' => [ 'find_type_constraint' ];
+=head1 CONSTANTS
+
+=head2 C<EPS>
+
+=cut
+
use constant EPS => 1e-10;
+=head1 FUNCTIONS
+
+=head2 C<numeq>
+
+=cut
+
sub numeq { abs($_[0] - $_[1]) < EPS }
+=head2 C<numcmp>
+
+=cut
+
sub numcmp { $_[0] < $_[1] - EPS ? -1 : $_[0] > $_[1] + EPS ? 1 : 0 }
+=head2 C<numround>
+
+=cut
+
sub numround {
my $x = $_[0];
my $i = int $x;
$x + EPS < $i + 0.5 ? $i : $i + 1;
}
+=head2 C<type_constraint $class>
+
+Find the type constraint for C<$class> by loading the relevant F<.pm> file beforehand.
+
+=cut
+
sub type_constraint {
my ($class) = @_;