File Coverage

blib/lib/Math/Geometry/Construction.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Math::Geometry::Construction;
2              
3 1     1   1436 use 5.008008;
  1         3  
  1         104  
4              
5 1     1   40 use Math::Geometry::Construction::Types qw(HashRefOfGeometricObject Draw);
  0            
  0            
6             use Carp;
7             use Moose;
8             use Math::Vector::Real 0.03;
9             use SVG;
10             use Params::Validate qw(validate validate_pos :types);
11             use List::Util qw(min);
12              
13             =head1 NAME
14              
15             C<Math::Geometry::Construction> - intersecting lines and circles
16              
17             =head1 VERSION
18              
19             Version 0.024
20              
21             =cut
22              
23             our $VERSION = '0.024';
24              
25              
26             ###########################################################################
27             # #
28             # Accessors #
29             # #
30             ###########################################################################
31              
32             has 'background' => (isa => 'Str|ArrayRef',
33             is => 'rw');
34              
35             has 'objects' => (isa => HashRefOfGeometricObject,
36             is => 'bare',
37             traits => ['Hash'],
38             default => sub { {} },
39             handles => {count_objects => 'count',
40             object => 'accessor',
41             object_ids => 'keys',
42             objects => 'values'},
43             init_arg => undef);
44              
45             has '_counter' => (isa => 'Int',
46             is => 'rw',
47             default => 0,
48             init_arg => undef);
49              
50             has 'point_size' => (isa => 'Num',
51             is => 'rw',
52             default => 6);
53              
54             has 'partial_circles' => (isa => 'Bool',
55             is => 'ro',
56             default => 0);
57              
58             has 'min_circle_gap' => (isa => 'Num',
59             is => 'ro',
60             default => 1.5707963267949);
61              
62             has 'buffer_results' => (isa => 'Bool',
63             is => 'rw',
64             default => 1,
65             trigger => \&clear_buffer);
66              
67             has '_output' => (isa => Draw,
68             is => 'rw',
69             handles => {draw_line => 'line',
70             draw_circle => 'circle',
71             draw_text => 'text'},
72             init_arg => undef);
73              
74             sub counter {
75             my ($self) = @_;
76              
77             my $counter = $self->_counter;
78             $self->_counter($counter + 1);
79             return $counter;
80             }
81              
82             sub clear_buffer {
83             my ($self) = @_;
84              
85             foreach($self->objects) {
86             $_->clear_buffer if($_->can('clear_buffer'));
87             }
88             }
89              
90             sub points {
91             my ($self) = @_;
92             my $class = 'Math::Geometry::Construction::Point';
93              
94             return(grep { $_->isa($class) } $self->objects);
95             }
96              
97             sub lines {
98             my ($self) = @_;
99             my $class = 'Math::Geometry::Construction::Line';
100              
101             return(grep { $_->isa($class) } $self->objects);
102             }
103              
104             sub circles {
105             my ($self) = @_;
106             my $class = 'Math::Geometry::Construction::Circle';
107              
108             return(grep { $_->isa($class) } $self->objects);
109             }
110              
111             sub add_object {
112             my ($self, $class, @args) = @_;
113              
114             if($class =~ /^\s*[A-Za-z0-9\_\:]+\s*$/) {
115             eval "require $class" or croak "Unable to load module $class: $!";
116             }
117             else { croak "Class name $class did not pass regex check" }
118            
119             my $object = $class->new(construction => $self,
120             @args,
121             order_index => $self->counter);
122             $self->object($object->id, $object);
123              
124             return $object;
125             }
126              
127             sub add_point {
128             my ($self, @args) = @_;
129              
130             return $self->add_object
131             ('Math::Geometry::Construction::FixedPoint', @args);
132             }
133              
134             sub add_line {
135             my ($self, @args) = @_;
136              
137             return $self->add_object
138             ('Math::Geometry::Construction::Line', @args);
139             }
140              
141             sub find_line {
142             my ($self, %args) = @_;
143              
144             # TODO: test %args
145            
146             foreach($self->lines) {
147             return $_ if($_->has_point(@{$args{support}}));
148             }
149             return undef;
150             }
151              
152             sub find_or_add_line {
153             my ($self, @args) = @_;
154              
155             return($self->find_line(@args) or $self->add_line(@args));
156             }
157              
158             sub add_circle {
159             my ($self, @args) = @_;
160              
161             return $self->add_object
162             ('Math::Geometry::Construction::Circle', @args);
163             }
164              
165             sub find_circle {
166             my ($self, %args) = @_;
167              
168             # TODO: test %args
169            
170             foreach($self->circles) {
171             return $_ if($_->center->id eq $args{center}->id and
172             $_->has_point($args{support}));
173             }
174             return undef;
175             }
176              
177             sub find_or_add_circle {
178             my ($self, @args) = @_;
179              
180             return($self->find_circle(@args) or $self->add_circle(@args));
181             }
182              
183             sub add_derivate {
184             my ($self, $class, @args) = @_;
185              
186             return $self->add_object
187             ('Math::Geometry::Construction::Derivate::'.$class, @args);
188             }
189              
190             sub add_derived_point {
191             my ($self, $class, $derivate_args, $point_args) = @_;
192              
193             my $derivate = $self->add_derivate($class, %$derivate_args);
194            
195             if(!defined($point_args) or ref($point_args) eq 'HASH') {
196             return $derivate->create_derived_point(%{$point_args || {}});
197             }
198             else {
199             return(map { $derivate->create_derived_point(%{$_ || {}}) }
200             @$point_args);
201             }
202             }
203              
204             ###########################################################################
205             # #
206             # Draw #
207             # #
208             ###########################################################################
209              
210             sub draw {
211             my ($self, $type, %args) = @_;
212              
213             ($type) = validate_pos(@{[$type]},
214             {type => SCALAR,
215             regex => qr/^\s*[A-Za-z0-9\_\:]+\s*$/});
216            
217             my $class = $type =~ /\:\:/
218             ? $type
219             : 'Math::Geometry::Construction::Draw::'.$type;
220              
221             eval "require $class" or croak "Unable to load module $class: $!";
222              
223             my $output = $self->_output
224             ($class->new(background => $self->background, %args));
225             my @objects = sort { $a->order_index <=> $b->order_index }
226             $self->objects;
227              
228             my $point_class = 'Math::Geometry::Construction::Point';
229             foreach(grep { !eval { $_->isa($point_class) } } @objects) {
230             $_->draw(output => $output) if($_->can('draw'));
231             }
232             foreach(grep { eval { $_->isa($point_class) } } @objects) {
233             $_->draw(output => $output) if($_->can('draw'));
234             }
235              
236             return $output->output;
237             }
238              
239             sub as_svg { return(shift(@_)->draw('SVG', @_)) }
240              
241             sub as_tikz { return(shift(@_)->draw('TikZ', @_)) }
242              
243             1;
244              
245              
246             __END__
247              
248             =pod
249              
250             =head1 SYNOPSIS
251              
252             use Math::Geometry::Construction;
253              
254             my $construction = Math::Geometry::Construction->new
255             (background => 'white');
256             my $p1 = $construction->add_point('x' => 100, 'y' => 150, hidden => 1);
257             my $p2 = $construction->add_point('x' => 120, 'y' => 150, hidden => 1);
258             my $p3 = $construction->add_point('x' => 200, 'y' => 50);
259             my $p4 = $construction->add_point('x' => 200, 'y' => 250);
260              
261             my $l1 = $construction->add_line(extend => 10,
262             label => 'g',
263             label_offset_y => 13,
264             support => [$p1, $p2]);
265             my $l2 = $construction->add_line(support => [$p3, $p4]);
266              
267             my $i1 = $construction->add_derivate('IntersectionLineLine',
268             input => [$l1, $l2]);
269             my $p5 = $i1->create_derived_point(label => 'S',
270             label_offset_x => 5,
271             label_offset_y => -5);
272              
273             my $c1 = $construction->add_circle(center => $p5, radius => 20);
274              
275             # an intersection point can also be generated in one go
276             my $p6 = $construction->add_derived_point
277             ('IntersectionCircleLine',
278             {input => [$l1, $c1]},
279             {position_selector => ['extreme_position', [[1, 0]]]});
280              
281             print $construction->as_svg(width => 800, height => 300)->xmlify;
282              
283              
284             =head1 DESCRIPTION
285              
286             This is alpha software. The API is stabilizing and the test suite at
287             least deserves that name by now, but input checks and documentation
288             are still sparse. However, release early, release often, so here we
289             go.
290              
291             =head2 Aims
292              
293             This distribution serves two purposes:
294              
295             =over 4
296              
297             =item * Carrying out geometric constructions like with compass and
298             straight edge. You can define points, lines through two points, and
299             circles around a given center and through a given point. You can let
300             these objects intersect to gain new points to work with.
301              
302             =item * Creating illustrations for geometry. This task is similar to
303             the one above, but not the same. For illustrations, the priorities
304             are usually different and more powerful tools like choosing a point
305             on a given object, drawing circles with fixed radius etc. are handy.
306              
307             =back
308              
309             =head2 Motivation
310              
311             Problems of these kinds can be solved using several pieces of
312             geometry software. However, I have not found any with sufficiently
313             powerful automization features. This problem has two aspects:
314              
315             =over 4
316              
317             =item * For some projects, I want to create many illustrations. I
318             have certain rules for the size of output images, usage of colors
319             etc.. With the programs I have used so far, I have found it
320             difficult to set these things in a consistent way for all of my
321             illustrations without the need to set them each time I start the
322             program or to change consistently later on.
323              
324             =item * For actual constructions, most macro languages are not
325             powerful enough. For example, the intersection between two circles
326             sometimes yields two points. There are situations where I want to
327             choose the one which is further away from some given point or the
328             one which is not the one I already had before or things like
329             that. The macro languages of most geometry programs do not allow
330             that. It is somehow determined internally which one is first
331             intersection point and which the second, so from the user point of
332             view the choice is arbitrary. Or, for example, I have come across
333             the situation where I needed to double an angle iteratively until it
334             becomes larger than a given angle. Impossible in most macro
335             languages. With C<Math::Geometry::Construction>, you have Perl as
336             your "macro language".
337              
338             =back
339              
340             =head2 Output Formats
341              
342             The current output formats are C<SVG> and C<TikZ>. Especially the
343             latter one is experimental and the interface might change in future
344             versions. Other output engines could be written by subclassing
345             L<Math::Geometry::Construction::Draw|Math::Geometry::Construction::Draw>.
346             However, documentation of the interface is not available, yet.
347              
348             =head2 Intersection Concept
349              
350             Intersecting two objects consists of two steps. First, you create a
351             L<Math::Geometry::Construction::Derivate|Math::Geometry::Construction::Derivate>
352             object that holds the intersecting partners and "knows" how to
353             calculate the intersection points. Second, you create a
354             L<Math::Geometry::Construction::DerivedPoint|Math::Geometry::Construction::DerivedPoint>
355             from the C<Derivate>. The C<DerivedPoint> object holds information
356             about which of the intersection points to use. This can be based on
357             distance to a given point, being the extreme point with respect to a
358             given direction etc..
359              
360             The C<DerivedPoint> object only holds information about how to
361             select the right point. Only when you ask for the position of the
362             point it is actually calculated. The purpose of this approach is
363             that you will always get the desired point based on the current
364             situation, even if you move your start configuration and the
365             arrangement of points changes.
366              
367             The classes are called C<Derivate> and C<DerivedPoint> because this
368             concept is applicable beyond the case of intersections. It could,
369             for example, be used to calculate the center of a circle given by
370             three points. Whenever some operation based on given objects results
371             in a finite number of points, it fits into this concept.
372              
373             =head2 Current Status
374              
375             At the moment, you can define points, lines, and circles. You can
376             intersect circles and lines with each other. The objects can have
377             labels, but the automatic positioning of the labels is very
378             primitive and unsatisfactory withouth polishing by the user.
379              
380             =head2 Next Steps
381              
382             =over 4
383              
384             =item * Extend documentation
385              
386             =item * Improve performance
387              
388             =item * Improve automatic positioning of labels
389              
390             =item * Improve test suite along the way
391              
392             =back
393              
394             =head1 INTERFACE
395              
396             =head2 Constructors
397              
398             =head3 new
399              
400             $construction = Math::Geometry::Construction->new(%args)
401              
402             Creates a new C<Math::Geometry::Construction> object and initializes
403             attributes. This is the default L<Moose|Moose> constructor.
404              
405              
406             =head2 Public Attributes
407              
408             =head3 background
409              
410             By default the background is transparent. This attribute can hold a
411             color to be used instead. Possible values depend on the output
412             type. For C<SVG>, it can hold any valid C<SVG> color specifier,
413             e.g. C<white> or C<rgb(255, 255, 255)>. C<TikZ> currently ignores
414             the C<background> attribute.
415              
416             =head3 objects
417              
418             A construction holds a hash of the objects it contains. The hash
419             itself is inaccessible. However, you can call the following
420             accessors:
421              
422             =over 4
423              
424             =item * count_objects
425              
426             Returns the number of objects. For the L<Moose|Moose> aficionado:
427             This is the C<count> method of the C<Hash> trait.
428              
429             =item * object
430              
431             $construction->object($key)
432             $construction->object($key, $value)
433              
434             Accessor/mutator method for single entries of the hash. The keys are
435             the object IDs. Usage of the mutator is not intended, use only to
436             tamper with the internals at your own risk.
437              
438             This is the C<accessor> method of the C<Hash> trait.
439              
440             =item * object_ids
441              
442             Returns a (copy of) the list of keys. This is the C<keys> method of
443             the C<Hash> trait.
444              
445             =item * objects
446              
447             Returns a (copy of) the list of values. This is the C<values> method
448             of the C<Hash> trait.
449              
450             =back
451              
452             As more specific accessors there are
453              
454             =over 4
455              
456             =item * points
457              
458             =item * lines
459              
460             =item * circles
461              
462             =back
463              
464             The C<points> list contains both user defined points and derived
465             points.
466              
467             =head3 point_size
468              
469             Holds the default point size that is used if no explict size is
470             given to C<Point> objects. Defaults to C<6>. Changing it will only
471             affect C<Point> objects created afterwards.
472              
473             =head2 Methods
474              
475             =head3 add_point
476              
477             $construction->add_point(%args)
478              
479             Returns a new
480             L<Math::Geometry::Construction::FixedPoint|Math::Geometry::Construction::FixedPoint> object.
481             All parameters are handed over to the constructor after adding the
482             C<construction> and C<order_index> arguments.
483              
484             Examples:
485              
486             $construction->add_point(position => [10, 20]);
487             $construction->add_point('x' => 50, 'y' => 30,
488             style => {stroke => 'red'});
489              
490             # requires 'use Math::Vector::Real' in this package
491             $construction->add_point(position => V(-15, 23),
492             hidden => 1);
493              
494             # NB: use of Math::VectorReal is still supported, but discouraged
495             # in favor of Math::Vector::Real
496             # requires 'use Math::VectorReal' in this package
497             $construction->add_point(position => vector(-1.3, 2.7, 0),
498             size => 10);
499              
500             =head3 add_line
501              
502             $construction->add_line(%args)
503              
504             Returns a new
505             L<Math::Geometry::Construction::Line|Math::Geometry::Construction::Line>
506             object. All parameters are handed over to the constructor after
507             adding the C<construction> and C<order_index> arguments.
508              
509             Example:
510              
511             $construction->add_line(support => [$point1, $point2],
512             extend => 10);
513              
514             =head3 add_circle
515              
516             $construction->add_circle(%args)
517              
518             Returns a new
519             L<Math::Geometry::Construction::Circle|Math::Geometry::Construction::Circle>
520             object. All parameters are handed over to the constructor after
521             adding the C<construction> and C<order_index> arguments.
522              
523             The "standard" circle requires the center and a "support" point on
524             its perimeter. However, you can provide a radius instead of the
525             support point, and the constructor of
526             L<Math::Geometry::Construction::Circle|Math::Geometry::Construction::Circle>
527             will create a support point under the hood. Even if you move the
528             center later on, the radius of the circle will stay constant.
529              
530             Examples:
531              
532             $construction->add_circle(center => $point1,
533             support => $point2);
534             $construction->add_circle(center => $point1,
535             radius => 50);
536              
537             =head3 add_derived_point
538              
539             $construction->add_derived_point($class, $derivate_args, $point_args)
540              
541             Combines the creation of a C<Derivate> object and a C<DerivedPoint>
542             object in one step.
543              
544             The method expects three parameters:
545              
546             =over 4
547              
548             =item 1. the derivate class
549              
550             =item 2. a hash reference with arguments for the constructor of
551             L<Math::Geometry::Construction::Derivate|Math::Geometry::Construction::Derivate>
552              
553             =item 3. a hash reference with arguments for the constructor of
554             L<Math::Geometry::Construction::DerivedPoint|Math::Geometry::Construction::DerivedPoint>; this argument is optional, if not defined it is replaced by an empty hash reference
555              
556             =back
557              
558             Returns the C<DerivedPoint> object.
559              
560             Example:
561              
562             $derived_point = $construction->add_derived_point
563             ('IntersectionLineLine',
564             {input => [$line1, $line2]},
565             {position_selector => ['indexed_point', [0]]});
566              
567             In this example, the last hash reference can be omitted:
568              
569             $derived_point = $construction->add_derived_point
570             ('IntersectionLineLine', {input => [$line1, $line2]});
571              
572             The missing hash reference is replaced by an empty hash reference,
573             and the constructor of the C<DerivedPoint> object uses the default
574             position selector C<['indexed_point', [0]]>.
575              
576             If multiple derived points based on the same derivative are desired
577             then the third argument for C<add_derived_point> can be replaced by
578             the reference to an array of hash references each of which holds the
579             parameters for one of the points. A list of C<DerivedPoint> objects
580             is returned.
581              
582             Example:
583              
584             @derived_points = $construction->add_derived_point
585             ('IntersectionCircleLine',
586             {input => [$circle, $line]},
587             [{position_selector => ['extreme_point', [[0, -1]]]},
588             {position_selector => ['extreme_point', [[0, 1]]]}]);
589              
590             In this case, we ask for the two intersection points between a
591             circle and a line. The C<extreme_point> position selector will give
592             us the most extreme of the intersection points in the given
593             direction. Therefore, in C<SVG> coordinates, C<$derived_points[0]>
594             will hold the "northern", C<$derived_points[1]> the "southern"
595             intersection point.
596              
597             =head3 add_derivate
598              
599             $construction->add_derivate($class, %args)
600              
601             Creates and returns a
602             L<Math::Geometry::Construction::Derivate|Math::Geometry::Construction::Derivate>
603             subclass instance. This can be used to create C<DerivedPoint>
604             objects. In most cases, it is convenient to perform these two steps
605             in one go, see L<add_derived_point|/add_derived_point>.
606              
607             This method is a convenience shortcut for L<add_object|/add_object>.
608             The only difference is that C<$class> is prepended with
609             C<Math::Geometry::Construction::Derivate::>. Therefore you can call
610              
611             $construction->add_derivate('IntersectionCircleLine', %args)
612              
613             instead of
614              
615             $construction->add_object
616             ('Math::Geometry::Construction::Derivate::IntersectionCircleLine', %args)
617              
618              
619             Example:
620              
621             $derivate = $construction->add_derivate('TranslatedPoint',
622             input => [$point],
623             translator => [10, -20]);
624             $point = $derivate->create_derived_point;
625              
626             =head3 add_object
627              
628             $construction->add_object($class, %args)
629              
630             Returns a new instance of the given class. All parameters are handed
631             over to the constructor after adding the C<construction> and
632             C<order_index> arguments. In fact, the methods above just call this
633             one with the appropriate class.
634              
635             =head3 as_svg
636              
637             $construction->as_svg(%args)
638             $construction->draw('SVG', %args)
639              
640             Shortcut for L<draw|/draw>. Returns an L<SVG|SVG> object
641             representing the construction. All parameters are handed over to the
642             L<SVG|SVG> constructor. At least C<width> and C<height> should be
643             provided.
644              
645             If a L<background color|/background> is specified then a rectangle
646             of that color is drawn as background. The size is taken from the
647             C<viewBox> attribute if specified, from C<width> and C<height>
648             otherwise. If none is given, no background is drawn.
649              
650             Example:
651              
652             my $svg = $construction->as_svg(width => 800,
653             height => 300);
654            
655             print $svg->xmlify;
656              
657             # or if SVG::Rasterize is installed...
658             my $rasterize = SVG::Rasterize->new();
659             $rasterize->rasterize(svg => $svg,
660             width => $width,
661             height => $height);
662             $rasterize->write(type => 'png',
663             file_name => 'construction.png');
664              
665              
666             =head3 as_tikz
667              
668             $construction->as_tikz(%args)
669             $construction->draw('TikZ', %args)
670              
671             Shortcut for L<draw|/draw>. Returns an L<LaTeX::TikZ|LaTeX::TikZ>
672             sequence object representing the construction. See
673             L<Math::Geometry::Construction::Draw|Math::Geometry::Construction::Draw>
674             and
675             L<Math::Geometry::Construction::Draw::TikZ|Math::Geometry::Construction::Draw::TikZ>
676             for supported parameters. At least C<width> and C<height> should be
677             provided.
678              
679             Example:
680              
681             my $tikz = $construction->as_tikz(width => 8,
682             height => 3);
683              
684             my (undef, undef, $body) = TikZ->formatter->render($tikz);
685            
686             printff("%s\n", join("\n", @$body));
687              
688             =head3 draw
689              
690             $construction->draw('SVG', %args)
691              
692             Draws the construction. The return value depends on the output type
693             and might be an object or a stringified version. Currently, the only
694             output types are C<SVG> and C<TikZ>. See L<as_svg|/as_svg> and
695             L<as_tikz|/as_tikz>.
696              
697             If the type does not contain a C<::> then it is prepended by
698             C<Math::Geometry::Construction::Draw::> before requiring the module.
699              
700             Calls the C<draw> method first on all non-point objects, then on
701             all C<Point> and C<DerivedPoint> objects. This is because I think
702             that points should be drawn on top of lines, circles etc..
703              
704              
705             =head2 List of Derivates
706              
707             =head2 Partial Drawing
708              
709             Each line or similar object holds a number of "points of
710             interest". These are - in case of the line - the two points that
711             define the line and all intersection points the line is involved
712             in. At drawing time, the object determines the most extreme points
713             and they define the end points of the drawn line segment. The
714             C<extend> attribute allows to extend the line for a given length
715             beyond these points because this often looks better. A similar
716             concept exist for circles.
717              
718             =head2 Reusing Objects
719              
720             =head2 Labels
721              
722              
723             =head1 DIAGNOSTICS
724              
725             =head2 Exceptions
726              
727             Currently, C<Math::Geometry::Construction> does not use any advanced
728             exception framework, it just croaks if it is unhappy. The error
729             messages are listed below in alphabetical order.
730              
731             =over 4
732              
733             =item * A line needs exactly two support points
734              
735             Thrown by the constructor of
736             L<Math::Geometry::Construction::Line|Math::Geometry::Construction::Line>
737             if the array referenced by the C<support> parameter does not contain
738             exactly two elements. The type of the elements is (not yet) checked
739             by L<Moose|Moose>.
740              
741             =item * Class name %s did not pass regex check
742              
743             =item * Need circles for CircleCircle intersection, no %s
744              
745             =item * Need one circle and one line to intersect
746              
747             The C<input> for circle line intersection has to be exactly one
748             L<Math::Geometry::Construction::Circle|Math::Geometry::Construction::Circle>
749             (or subclass) object and one
750             L<Math::Geometry::Construction::Line|Math::Geometry::Construction::Line>
751             (or subclass) object. This exception is thrown in all other
752             cases. It might be split into more specific exceptions in the
753             future. The exception is thrown only when the positions of the
754             intersections are calculated.
755              
756             =item * Need lines for LineLine intersection, no %s
757              
758             The C<input> for line line intersection has to consist of exactly
759             two
760             L<Math::Geometry::Construction::Line|Math::Geometry::Construction::Line>
761             (or subclass) objects. If the correct number of items is given, but
762             one of them is of an incorrect type then this exception is thrown.
763              
764             =item * Need one line for PointOnLine"
765              
766             =item * Need one point
767              
768             =item * Need something with a position, no %s
769              
770             =item * Need two circles to intersect
771              
772             =item * Need two lines to intersect
773              
774             The C<input> for line line intersection has to consist of exactly
775             two
776             L<Math::Geometry::Construction::Line|Math::Geometry::Construction::Line>
777             (or subclass) objects. If the wrong number of C<input> items
778             (ignoring their values) is given then this exception is thrown. The
779             exception is thrown only when the position of the intersection is
780             calculated.
781              
782             =item * No way to determine position of PointOnLine %s
783              
784             =item * Position of PointOnLine has to be set somehow
785              
786             When constructing a
787             L<Math::Geometry::Construction::Derivate::PointOnLine|Math::Geometry::Construction::Derivate::PointOnLine>
788             object, one of the attributes C<distance>, C<quantile>, C<x>, and
789             C<y> has to be specified. Otherwise this exception is thrown.
790              
791             =item * Unable to load module %s: %s
792              
793             =item * Undefined direction in 'extreme_position' selector
794              
795             The C<extreme_position> position selector expects a direction
796             vector. This exception is raised if the provided direction is
797             undefined.
798              
799             =item * Undefined index in 'indexed_position' selector"
800              
801             The C<indexed_position> position selector expects an index. This
802             exception is raised if the provided index is undefined.
803              
804             =item * Undefined reference position in '%s' selector
805              
806             The C<close_position> and C<distant_position> position selectors
807             expect a reference position. This exception is raised if the
808             provided reference is undefined.
809              
810             =item * Unsupported vector format %s
811              
812             =back
813              
814              
815             =head2 Warnings
816              
817             =over 4
818              
819             =item * Failed to parse viewBox attribute.
820              
821             =item * Method position must be overloaded
822              
823             =item * Method id must be overloaded
824              
825             =item * No positions to select from in %s.
826              
827             This warning is issued by the position selectors if there is are no
828             positions. For example, if you are using an intersection point of
829             two circles, but the circles do not intersect. The position selector
830             will print this warning and return undef. Your downstream code must
831             be able to handle undefined positions.
832              
833             =item * Position index out of range in %s.
834              
835             =item * The 'radius' attribute of
836             Math::Geometry::Construction::Point is deprecated and might be
837             removed in a future version. Use 'size' with the double
838             value (diameter of the circle) instead.
839              
840             I think this message speaks for itself :-).
841              
842             =item * Support points of line %s are identical, cannot determine
843             normal.
844              
845             =item * Undefined center of circle %s, nothing to draw.
846              
847             =item * Undefined position of point %s, nothing to draw.
848              
849             =item * Undefined support of circle %s, nothing to draw.
850              
851             =item * Undefined support point in line %s, cannot determine normal.
852              
853             =item * Undefined support point in line %s, nothing to draw.
854              
855             =back
856              
857              
858             =head1 BUGS AND LIMITATIONS
859              
860             Please report any bugs or feature requests to
861             C<bug-math-geometry-construction at rt.cpan.org>, or through the web
862             interface at
863             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Math-Geometry-Construction>.
864             I will be notified, and then you will automatically be notified of
865             progress on your bug as I make changes.
866              
867              
868             =head1 AUTHOR
869              
870             Lutz Gehlen, C<< <perl at lutzgehlen.de> >>
871              
872              
873             =head1 LICENSE AND COPYRIGHT
874              
875             Copyright 2011-2013 Lutz Gehlen.
876              
877             This program is free software; you can redistribute it and/or modify it
878             under the terms of either: the GNU General Public License as published
879             by the Free Software Foundation; or the Artistic License.
880              
881             See http://dev.perl.org/licenses/ for more information.
882              
883             =cut