File Coverage

blib/lib/Math/Geometry/Construction/Line.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Math::Geometry::Construction::Line;
2 1     1   2247 use Moose;
  0            
  0            
3              
4             use 5.008008;
5              
6             use Math::Geometry::Construction::Types qw(PointPoint);
7             use Carp;
8             use List::MoreUtils qw(any);
9             use Scalar::Util qw(blessed);
10             use Math::Vector::Real;
11              
12             use overload 'x' => '_intersect',
13             '.' => '_point_on',
14             'bool' => sub { return 1 };
15              
16             =head1 NAME
17              
18             C<Math::Geometry::Construction::Line> - line through two points
19              
20             =head1 VERSION
21              
22             Version 0.024
23              
24             =cut
25              
26             our $VERSION = '0.024';
27              
28              
29             ###########################################################################
30             # #
31             # Class Variables and Methods #
32             # #
33             ###########################################################################
34              
35             our $ID_TEMPLATE = 'L%09d';
36              
37             sub id_template { return $ID_TEMPLATE }
38              
39             ###########################################################################
40             # #
41             # Accessors #
42             # #
43             ###########################################################################
44              
45             with 'Math::Geometry::Construction::Role::Input';
46             with 'Math::Geometry::Construction::Role::Object';
47             with 'Math::Geometry::Construction::Role::PositionSelection';
48             with 'Math::Geometry::Construction::Role::Output';
49             with 'Math::Geometry::Construction::Role::PointSet';
50              
51             has 'support' => (isa => PointPoint,
52             is => 'bare',
53             traits => ['Array'],
54             required => 1,
55             handles => {count_support => 'count',
56             support => 'elements',
57             single_support => 'accessor'});
58              
59             sub BUILDARGS {
60             my ($class, %args) = @_;
61            
62             for(my $i=0;$i<@{$args{support}};$i++) {
63             $args{support}->[$i] = $class->import_point
64             ($args{construction}, $args{support}->[$i]);
65             }
66              
67             return \%args;
68             }
69              
70             sub BUILD {
71             my ($self, $args) = @_;
72              
73             $self->style('stroke', 'black') unless($self->style('stroke'));
74              
75             $self->register_point($self->support);
76             }
77              
78             ###########################################################################
79             # #
80             # Retrieve Data #
81             # #
82             ###########################################################################
83              
84             sub positions {
85             my ($self) = @_;
86              
87             return map { $_->position } $self->points;
88             }
89              
90             sub direction {
91             my ($self) = @_;
92             my @support_positions = map { $_->position } $self->support;
93              
94             # check for defined positions
95             if(any { !defined($_) } @support_positions) {
96             warn sprintf("Undefined support point in line %s.\n", $self->id);
97             return undef;
98             }
99              
100             return($support_positions[1] - $support_positions[0]);
101             }
102              
103             sub parallel {
104             my ($self) = @_;
105             my @support_positions = map { $_->position } $self->support;
106              
107             # check for defined positions
108             if(any { !defined($_) } @support_positions) {
109             warn sprintf("Undefined support point in line %s.\n", $self->id);
110             return undef;
111             }
112              
113             my $direction = $support_positions[1] - $support_positions[0];
114             my $length = abs($direction);
115              
116             if($length == 0) {
117             warn sprintf("Support points of line %s are identical.\n",
118             $self->id);
119             return undef;
120             }
121            
122             return($direction / $length);
123             }
124              
125             sub normal {
126             my ($self) = @_;
127             my $parallel = $self->parallel;
128              
129             return $parallel ? V(-$parallel->[1], $parallel->[0]) : undef;
130             }
131              
132             sub draw {
133             my ($self, %args) = @_;
134             return undef if $self->hidden;
135              
136             my $parallel = $self->parallel;
137             return undef if(!$parallel);
138              
139             my $extend = $self->extend;
140             my @positions = ($self->extreme_position(-$parallel)
141             - $parallel * $extend->[0],
142             $self->extreme_position($parallel)
143             + $parallel * $extend->[1]);
144              
145             $self->construction->draw_line(x1 => $positions[0]->[0],
146             y1 => $positions[0]->[1],
147             x2 => $positions[1]->[0],
148             y2 => $positions[1]->[1],
149             style => $self->style_hash,
150             id => $self->id);
151            
152             $self->draw_label
153             ('x' => ($positions[0]->[0] + $positions[1]->[0]) / 2,
154             'y' => ($positions[0]->[1] + $positions[1]->[1]) / 2);
155             }
156              
157             ###########################################################################
158             # #
159             # Overloading #
160             # #
161             ###########################################################################
162              
163             sub _intersect {
164             my ($self, $intersector) = @_;
165             my $class;
166            
167             $class = 'Math::Geometry::Construction::Line';
168             if(eval { $intersector->isa($class) }) {
169             return $self->construction->add_derived_point
170             ('IntersectionLineLine', {input => [$self, $intersector]});
171             }
172              
173             $class = 'Math::Geometry::Construction::Circle';
174             if(eval { $intersector->isa($class) }) {
175             return $self->construction->add_derived_point
176             ('IntersectionCircleLine', {input => [$self, $intersector]});
177             }
178             }
179              
180             sub _point_on {
181             my ($self, $args) = @_;
182              
183             my $derivate = "Math::Geometry::Construction::Derivate::PointOnLine";
184             return $self->construction->add_derived_point
185             ($derivate, {input => [$self], $args});
186             }
187              
188             1;
189              
190              
191             __END__
192              
193             =pod
194              
195             =head1 SYNOPSIS
196              
197             my $p1 = $construction->add_point('x' => 100, 'y' => 90);
198             my $p2 = $construction->add_point('x' => 120, 'y' => 150);
199             my $l1 = $construction->add_line(support => [$p1, $p2]);
200              
201             my $p3 = $construction->add_point('x' => 200, 'y' => 50);
202             my $p4 = $construction->add_point('x' => 250, 'y' => 50);
203              
204             my $l2 = $construction->add_line(support => [$p3, $p4],
205             extend => 10,
206             label => 'g',
207             label_offset_y => 13);
208              
209              
210             =head1 DESCRIPTION
211              
212             An instance of this class represents a line defined by two points.
213             The points can be either points defined directly by the user
214             (L<Math::Geometry::Construction::Point|Math::Geometry::Construction::Point>
215             objects) or so-called derived points
216             (L<Math::Geometry::Construction::DerivedPoint|Math::Geometry::Construction::DerivedPoint>
217             objects), e.g. intersection points. This class is not supposed to be
218             instantiated directly. Use the L<add_line
219             method|Math::Geometry::Construction/add_line> of
220             C<Math::Geometry::Construction> instead.
221              
222              
223             =head1 INTERFACE
224              
225             =head2 Public Attributes
226              
227             =head3 support
228              
229             Holds an array reference of the two points that define the line.
230             Must be given to the constructor and should not be touched
231             afterwards (the points can change their positions, of course). Must
232             hold exactly two points.
233              
234             =head3 extend
235              
236             Often it looks nicer if the visual representation of a line extends
237             somewhat beyond its end points. The length of this extent is set
238             here. Internally, this is an array reference with two entries
239             containing the exent in backward in forward direction. If a single
240             value C<x> is provided it is turned into C<[x, x]>. Defaults to
241             C<[0, 0]>.
242              
243             Take care if you are reading this attribute. You get the internal
244             array reference, so manipulating it will affect the values stored in
245             the object.
246              
247             =head2 Methods
248              
249             =head3 direction
250              
251             Returns the unnormalized difference vector between the two support
252             points as a L<Math::Vector::Real|Math::Vector::Real>. Issues a
253             warning and returns C<undef> if one of the support points has an
254             undefined position. If the support points have identical positions
255             the C<0> vector is returned without warning.
256              
257             =head3 parallel
258              
259             Returns a L<Math::Vector::Real|Math::Vector::Real> of length C<1>
260             that is parallel to the line. Issues a warning and returns C<undef>
261             if one of the support points has an undefined position or if the two
262             positions are identical.
263              
264             =head3 normal
265              
266             Returns a L<Math::Vector::Real|Math::Vector::Real> of length C<1>
267             that is orthogonal to the line. Issues a warning and returns
268             C<undef> if one of the support points has an undefined position or
269             if the two positions are identical.
270              
271             =head3 draw
272              
273             Called by the C<Construction> object during output generation.
274             Draws a line between the most extreme points on this line
275             (including both support points and points derived from this line).
276             The line is extended by length of L<extend|/extend> beyond these
277             points.
278              
279             =head3 id_template
280              
281             Class method returning C<$ID_TEMPLATE>, which defaults to C<'L%09d'>.
282              
283              
284             =head1 AUTHOR
285              
286             Lutz Gehlen, C<< <perl at lutzgehlen.de> >>
287              
288              
289             =head1 LICENSE AND COPYRIGHT
290              
291             Copyright 2011-2013 Lutz Gehlen.
292              
293             This program is free software; you can redistribute it and/or modify it
294             under the terms of either: the GNU General Public License as published
295             by the Free Software Foundation; or the Artistic License.
296              
297             See http://dev.perl.org/licenses/ for more information.
298              
299              
300             =cut
301