The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Math::Geometry::Construction - intersecting lines and circles

VERSION

Version 0.009

SYNOPSIS

  use Math::Geometry::Construction;

  my $construction = Math::Geometry::Construction->new
      (background => 'white');
  my $p1 = $construction->add_point('x' => 100, 'y' => 150, hidden => 1);
  my $p2 = $construction->add_point('x' => 120, 'y' => 150, hidden => 1);
  my $p3 = $construction->add_point('x' => 200, 'y' => 50);
  my $p4 = $construction->add_point('x' => 200, 'y' => 250);

  my $l1 = $construction->add_line(extend         => 10,
                                   label          => 'g',
                                   label_offset_y => 13,
                                   support        => [$p1, $p2]);
  my $l2 = $construction->add_line(support => [$p3, $p4]);

  my $i1 = $construction->add_derivate('IntersectionLineLine',
                                       input => [$l1, $l2]);
  my $p5 = $i1->create_derived_point
        (position_selector => ['indexed_position', [0]],
         label             => 'S',
         label_offset_x    => 5,
         label_offset_y    => -5);

  print $construction->as_svg(width => 800, height => 300)->xmlify;

DESCRIPTION

This is alpha software. The API is likely to change, input checks and documentation are sparse, the test suite barely exists. But release early, release often, so here we go.

So far, the development has been fast and focused on adding features. On the downside, the code has to be considered fragile. Please report any problems you encounter.

Aims

This distribution serves two purposes:

  • Carrying out geometric constructions like with compass and straight edge. You can define points, lines through two points, and circles around a given center and through a given point. You can let these objects intersect to gain new points to work with.

  • Creating illustrations for geometry. This task is similar to the one above, but not the same. For illustrations, the priorities are usually different and more powerful tools like choosing a point on a given object, drawing circles with fixed radius etc. are handy.

Motivation

Problems of these kinds can be solved using several pieces of geometry software. However, I have not found any with sufficiently powerful automization features. This problem has two aspects:

  • For some project, I want to create many illustrations. I have certain rules for the size of output images, usage of colors etc.. With the programs I have used so far, I have found it difficult to set these things in a consistent way for all of my illustrations without the need to set them each time I start the program or to change consistently later on.

  • For actual constructions, most macro languages are not powerful enough. For example, the intersection between two circles sometimes yields two points. There are situations where I want to choose the one which is further away from some given point or the one which is not the one I already had before or things like that. The macro languages of most geometry programs do not allow that. It is somehow determined internally which one is first intersection point and which the second, so from the user point of view the choice is arbitrary. Or, for example, I have come across the situation where I needed to double an angle iteratively until it becomes larger than a given angle. Impossible in most macro languages. With this module, you have Perl as your "macro language".

Intersection Concept

Intersecting two objects consists of two steps. First, you create a Math::Geometry::Construction::Derivate object that holds the intersecting partners and "knows" how to calculate the intersection points. Second, you create a Math::Geometry::Construction::DerivedPoint from the Derivate. The DerivedPoint object holds information about which of the intersection points to use. This can be based on distance to a given point, being the extreme point with respect to a given direction etc..

The DerivedPoint object only holds information about how to select the right point. Only when you ask for the position of the point it is actually calculated.

The classes are called Derivate and DerivedPoint because this concept is applicable beyond the case of intersections. It could, for example, be used to calculate the center of a circle given by three points. Whenever some operation based on given objects results in a finite number of points, it fits into this concept.

Output

Output Formats

The current output formats are SVG and TikZ. Especially the latter one is experimental and the interface might change in future versions. Other output engines could be written by subclassing Math::Geometry::Construction::Draw. However, documentation of the interface is not available, yet.

How much to draw?

Each line or similar object holds a number of "points of interest". These are - in case of the line - the two points that define the line and all intersection points the line is involved in. At drawing time, the object determines the most extreme points and they define the end points of the drawn line segment. The extend attribute allows to extend the line for a given length beyond these points because this often looks better. A similar concept will be implemented for circles, but currently, the full circle is drawn.

Current Status

At the moment, you can define points, lines, and circles. You can intersect circles and lines with each other. The objects can have labels, but the automatic positioning of the labels is very primitive and unsatisfactory withouth polishing by the user.

Next Steps

  • Extend documentation

  • Improve performance

  • Improve automatic positioning of labels

  • Improve test suite along the way

INTERFACE

Constructors

new

  $construction = Math::Geometry::Construction->new(%args)

Creates a new Math::Geometry::Construction object and initializes attributes. This is the default Moose constructor.

Public Attributes

background

By default the background is transparent. This attribute can hold a color to be used instead. Possible values depend on the output type. For SVG, it can hold any valid SVG color specifier, e.g. white or rgb(255, 255, 255). TikZ currently ignores the background attribute.

objects

A construction holds a hash of the objects it contains. The hash itself is inaccessible. However, you can call the following accessors:

  • count_objects

    Returns the number of objects. For the Moose aficionado: This is the count method of the Hash trait.

  • object

      $construction->object($key)
      $construction->object($key, $value)

    Accessor/mutator method for single entries of the hash. The keys are the object IDs. Usage of the mutator is not intended, use only to tamper with the internals at your own risk.

    This is the accessor method of the Hash trait.

  • object_ids

    Returns a (copy of) the list of keys. This is the keys method of the Hash trait.

  • objects

    Returns a (copy of) the list of values. This is the values method of the Hash trait.

Methods for Users

add_point

  $construction->add_point(%args)

Returns a new Math::Geometry::Construction::Point. All parameters are handed over to the constructor after adding the construction and order_index arguments.

Example:

  $construction->add_point('x' => 10, 'y' => 20,
                           style => {stroke => 'red'});

add_line

  $construction->add_line(%args)

Returns a new Math::Geometry::Construction::Line. All parameters are handed over to the constructor after adding the construction and order_index arguments.

Example:

  $construction->add_line(support => [$point1, $point2],
                          extend  => 10);

add_circle

  $construction->add_circle(%args)

Returns a new Math::Geometry::Construction::Circle. All parameters are handed over to the constructor after adding the construction and order_index arguments.

Example:

  $construction->add_circle(center  => $point1,
                            support => $point1);

add_object

  $construction->add_object($class, %args)

Returns a new instance of the given class. All parameters are handed over to the constructor after adding the construction and order_index arguments. In fact, add_point, add_line, and add_circle just call this method with the appropriate class.

add_derivate

  $construction->add_derivate($class, %args)

Convenience shortcut for add_object. The only difference is that $class is prepended with Math::Geometry::Construction::Derivate::. Therefore you can call

  $construction->add_derivate('IntersectionCircleLine', %args)

instead of

  $construction->add_object
      ('Math::Geometry::Construction::Derivate::IntersectionCircleLine', %args)

Example:

  $construction->add_derivate('TranslatedPoint',
                              input      => [$point1],
                              translator => vector(10, -20, 0));

add_derived_point

  $construction->add_derived_point($class, $derivate_args, $point_args)

Combines the creation of a Derivate object and a DerivedPoint object in one step. This is particularly useful if the derivate only holds one point, e.g. the intersection of two lines, a translated point, a point on a line etc..

The method expects three parameters:

1. the derivate class
2. a hash reference with arguments for the constructor of Math::Geometry::Construction::Derivate
3. a hash reference with arguments for the constructor of Math::Geometry::Construction::DerivedPoint; this argument is optional, if not defined it is replaced by an empty hash reference

Returns the DerivedPoint object.

Example:

  $derived_point = $construction->add_derived_point
      ('IntersectionLineLine',
       {input      => [$line1, $line2]},
       {position_selector => ['indexed_point', [0]]});

In this example, the last hash reference can be omitted:

  $derived_point = $construction->add_derived_point
      ('IntersectionLineLine', {input => [$line1, $line2]});

The missing hash reference is replaced by an empty hash reference, and the constructor of the DerivedPoint object uses the default position selector ['indexed_point', [0]].

If multiple derived points based on the same derivative are desired then the third argument for add_derived_point can be replaced by the reference to an array of hash references each of which holds the parameters for one of the points. A list of DerivedPoint objects is returned.

Example:

  use Math::VectorReal;

  @derived_points = $construction->add_derived_point
      ('IntersectionCircleLine',
       {input      => [$circle, $line]},
       [{position_selector => ['extreme_point', [vector(0, -1, 0)]]},
        {position_selector => ['extreme_point', [vector(0,  1, 0)]]}]);

In this case, we ask for the two intersection points between a circle and a line. The extreme_point position selector will give as the most extreme of the intersection points in the given direction. Therefore, in SVG coordinates, $derived_points[0] will hold the "northern", $derived_points[1] the "southern" intersection point.

draw

  $construction->draw('SVG', %args)

Draws the construction. The return value depends on the output type and might be an object or a stringified version. Currently, the only output type is SVG. See as_svg.

If the type does not contain a :: then it is prepended by Math::Geometry::Construction::Draw:: before requiring the module.

Calls the draw method first on all non-point objects, then on all Point and DerivedPoint objects. This is because I think that points should be drawn on top of lines, circles etc..

as_svg

  $construction->as_svg(%args)
  $construction->draw('SVG', %args)

Shortcut for draw. Returns an SVG object representing the construction. All parameters are handed over to the SVG constructor. At least width and height should be provided.

If a background color is specified then a rectangle of of that color is drawn as background. The size is taken from the viewBox attribute if specified, from width and height otherwise. If none is given, no background is drawn.

as_tikz

  $construction->as_tikz(%args)
  $construction->draw('TikZ', %args)

Shortcut for draw. Returns an LaTeX sequence object representing the construction. See Math::Geometry::Construction::Draw and Math::Geometry::Construction::Draw::TikZ for supported parameters. At least width and height should be provided.

DIAGNOSTICS

Exceptions

Warnings

BUGS AND LIMITATIONS

Please report any bugs or feature requests to bug-math-geometry-construction at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Math-Geometry-Construction. I will be notified, and then you will automatically be notified of progress on your bug as I make changes.

AUTHOR

Lutz Gehlen, <perl at lutzgehlen.de>

LICENSE AND COPYRIGHT

Copyright 2011 Lutz Gehlen.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.