Eric Wilhelm >
CAD-Calc >
CAD::Calc

Module Version: 0.27
- NAME
- AUTHOR
- COPYRIGHT
- LICENSE
- NO WARRANTY
- Modifications
- Configuration
- Constants
- Functions
- distdivide
- subdivide
- shorten_line
- dist
- dist2d
- line_vec
- slope
- segs_as_transform
- chevron_to_ray
- signdist
- offset
- intersection_data
- line_intersection
- seg_line_intersection
- seg_seg_intersection
- line_ray_intersection
- seg_ray_intersection
- ray_pgon_int_index
- ray_pgon_closest_index
- perp_through_point
- foot_on_line
- foot_on_segment
- Determinant
- pgon_as_segs
- pgon_area
- pgon_centroid
- pgon_lengths
- pgon_angles
- pgon_deltas
- ang_deltas
- pgon_direction
- angs_direction
- pgon_bisectors
- sort_pgons_lr
- pgon_start_index
- pgon_start_indexb
- pgon_start_index_z
- re_order_pgon
- order_pgon
- shift_line
- line_to_rectangle
- isleft
- howleft
- iswithin
- iswithinc
- unitleft
- unitright
- unit_angle
- angle_reduce
- angle_parse
- angle_quadrant
- collinear
- triangle_angles
- stringify
- stringify_line
- pol_to_cart
- cart_to_pol
- print_line
- point_avg
- arc_2pt

CAD::Calc - generic cad-related geometry calculations

Eric Wilhelm @ <ewilhelm at cpan dot org>

This module is copyright (C) 2004, 2005, 2006, 2008 Eric L. Wilhelm. Portions copyright (C) 2003 by Eric L. Wilhelm and A. Zahner Co.

This module is distributed under the same terms as Perl. See the Perl source package for details.

You may use this software under one of the following licenses:

(1) GNU General Public License (found at http://www.gnu.org/copyleft/gpl.html) (2) Artistic License (found at http://www.perl.com/pub/language/misc/Artistic.html)

This software is distributed with ABSOLUTELY NO WARRANTY. The author, his former employer, and any other contributors will in no way be held liable for any loss or damages resulting from its use.

The source code of this module is made freely available and distributable under the GPL or Artistic License. Modifications to and use of this software must adhere to one of these licenses. Changes to the code should be noted as such and this notification (as well as the above copyright information) must remain intact on all copies of the code.

Additionally, while the author is actively developing this code, notification of any intended changes or extensions would be most helpful in avoiding repeated work for all parties involved. Please contact the author with any such development plans.

Used to set package global values such as precision.

Not called directly. Triggered by the use() function.

import(%options, @EXPORT_TAGS);

Example:

use CAD::Calc ( -precision => 0.125, -angular => 1.0e-6, qw( seg_seg_intersection dist2d print_line ) );

Returns the value of $CAD::Calc::pi

pi;

These are all exported as options.

Returns a list of point references resulting from dividing $line into as many parts as possible which are at least $dist apart.

@points = distdivide(\@line, $dist);

Returns a list of point references resulting from subdividing $line into $count parts. The list will be $count-1 items long, (does not include $line->[0] and $line->[1]);

$line is of the form: [ [x1, y1, z1], [x2, y2, z2] ] where z1 and z2 are optional.

@points = subdivide($line, $count);

Shortens the line by the distances given in $lead and $tail.

@line = shorten_line(\@line, $lead, $tail);

Returns the direct distance from ptA to ptB.

dist($ptA, $ptB);

Purposefully ignores a z (2) coordinate.

dist2d($ptA, $ptB);

Returns a Math::Vec object representing the vector from $ptA to $ptB (which is actually a segment.)

$vec = line_vec($ptA, $ptB);

Calculates the 2D slope between points @ptA and @ptB. Slope is defined as dy / dx (rise over run.)

If dx is 0, will return the string "inf", which Perl so kindly treats as you would expect it to (except it doesn't like to answer the question "what is infinity over infinity?") 5.8.? users: sorry, there seems to be some regression here! (now we're using Math::BigFloat to return inf, so rounding has to go through that)

$slope = slope(\@ptA, \@ptB);

Allows two segments to specify transform data.

Returns: (\@translate, $rotate, $scale),

where:

@translate is a 2D array [$x, $y] basically describing segment @A

$rotate is the angular difference between $A[0]->$B[0] and $A[1]->$B[1]

$scale is the length of $A[1]->$B[1] divided by the length of $A[0]->$B[0]

my ($translate, $rotate, $scale) = segs_as_transform(\@A, \@B);

Converts a chevron into a directional line by finding the midpoint between the midpoints of each edge and connecting to the middle point.

@line = chevron_to_ray(@pts);

Returns the signed distance

signdist(\@ptA, \@ptB);

Creates a contour representing the offset of @polygon by $dist. Positive distances are inward when @polygon is ccw.

@polygons = offset(\@polygon, $dist);

Calculates the two numerators and the denominator which are required for various (seg-seg, line-line, ray-ray, seg-ray, line-ray, line-seg) intersection calculations.

($k, $l, $d) = intersection_data(\@line, \@line);

Returns the intersection point of two lines.

@pt = line_intersection(\@line, \@line, $tolerance); @pt or die "no intersection";

If tolerance is defined, it will be used to sprintf the parallel factor. Beware of this, it is clunky and might change if I come up with something better.

Finds the intersection of @segment and @line.

my @pt = seg_line_intersection(\@segment, \@line); @pt or die "no intersection"; unless(defined($pt[1])) { die "lines are parallel"; }

my @pt = seg_seg_intersection(\@segmenta, \@segmentb);

Intersects @line with @ray, where $ray[1] is the direction of the infinite ray.

line_ray_intersection(\@line, \@ray);

Intersects @seg with @ray, where $ray[1] is the direction of the infinite ray.

seg_ray_intersection(\@seg, \@ray);

Returns the first (lowest) index of @polygon which has a segment intersected by @ray.

$index = ray_pgon_int_index(\@ray, \@polygon);

Returns the closest (according to dist2d) index of @polygon which has a segment intersected by @ray.

$index = ray_pgon_closest_index(\@ray, \@polygon);

@line = perp_through_point(\@pt, \@line);

@pt = foot_on_line(\@pt, \@line);

Returns the perpendicular foot of @pt on @seg. See seg_ray_intersection.

@pt = foot_on_segment(\@pt, \@seg);

Determinant($x1, $y1, $x2, $y2);

Returns a list of [[@ptA],[@ptB]] segments representing the edges of @pgon, where segment "0" is from $pgon[0] to $pgon[1]

@segs = pgon_as_segs(@pgon);

Returns the area of @polygon. Returns a negative number for clockwise polygons.

$area = pgon_area(@polygon);

@centroid = pgon_centroid(@polygon);

@lengths = pgon_lengths(@pgon);

Returns the angle of each edge of polygon in xy plane. These fall between -$pi and +$pi due to the fact that it is basically just a call to the atan2() builtin.

Edges are numbered according to the index of the point which starts the edge.

@angles = pgon_angles(@points);

Returns the differences between the angles of each edge of @polygon. These will be indexed according to the point at which they occur, and will be positive radians for ccw angles. Summing the @deltas will yield +/-2pi (negative for cw polygons.)

@deltas = pgon_deltas(@pgon);

Returns the same thing as pgon_deltas, but saves a redundant call to pgon_angles.

my @angs = pgon_angles(@pts); my @dels = ang_deltas(@angs);

Returns 1 for counterclockwise and 0 for clockwise. Uses the sum of the differences of angles of @polygon. If this sum is less than 0, the polygon is clockwise.

$ang_sum = pgon_direction(@polygon);

Returns the same thing as pgon_direction, but saves a redundant call to pgon_deltas.

my @angs = pgon_deltas(@pgon); my $dir = angs_direction(@angs);

pgon_bisectors();

Sorts polygons by their average points returning a list which reads from left to right. (Rather odd place for this?)

@pgons = sort_pgons_lr(@pgons);

Returns the index of pgon which is at the "lowest left".

$i = pgon_start_index(@pgon);

Returns the index of pgon which is at the "lowest left".

Different method (is it faster?)

$i = pgon_start_indexb(@pgon);

Yet another different method (is this even correct?)

pgon_start_index_z();

Imposes counter-clockwise from "lower-left" ordering.

@pgon = re_order_pgon(@pgon);

Rewinds the polygon (e.g. list) to the specified $start index. This is not restricted to polygons (just continuous (looped) lists.)

@pgon = order_pgon($start, \@pgon);

Shifts line to right or left by $distance.

@line = shift_line(\@line, $distance, right|left);

Creates a rectangle, centered about @line.

my @rec = line_to_rectangle(\@line, $offset, \%options);

The direction of the returned points will be counter-clockwise around the original line, with the first point at the 'lower-left' (e.g. if your line points up, $rec[0] will be below and to the left of $line[0].)

Available options

ends => 1|0, # extend endpoints by $offset (default = 1)

Returns true if @point is left of @line.

$bool = isleft(\@line, \@point);

Returns positive if @point is left of @line.

$number = howleft(\@line, \@point);

Returns true if @pt is within the polygon @bound. This will be negative for clockwise input.

$fact = iswithin(\@bound, \@pt);

Seems to be consistently much faster than the typical winding-number iswithin. The true return value is always positive regardless of the polygon's direction.

$fact = iswithinc(\@bound, \@pt);

Returns a unit vector which is perpendicular and to the left of @line. Purposefully ignores any z-coordinates.

$vec = unitleft(@line);

Negative of unitleft().

$vec = unitright(@line);

Returns a Math::Vec vector which has a length of one at angle $ang (in the XY plane.) $ang is fed through angle_parse().

$vec = unit_angle($ang);

Reduces $ang (in radians) to be between -pi and +pi.

$ang = angle_reduce($ang);

Parses the variable $ang and returns a variable in radians. To convert degrees to radians: $rad = angle_parse($deg . "d")

$rad = angle_parse($ang);

Returns the index of the quadrant which contains $angle. $angle is in radians.

$q = angle_quadrant($angle); @syms = qw(I II III IV); print "angle is in quadrant: $syms[$q]\n";

$fact = collinear(\@pt1, \@pt2, \@pt3);

Calculates the angles of a triangle based on it's lengths.

@angles = triangle_angles(@lengths);

The order of the returned angle will be "the angle before the edge".

Turns point into a string rounded according to $rnd. The optional $count allows you to specify how many coordinates to use.

$string = stringify(\@pt, $rnd, $count);

Turns a line (or polyline) into a string. See stringify().

stringify_line(\@line, $char, $rnd, $count);

Convert from polar to cartesian coordinates.

my ($x, $y, $z) = pol_to_cart($radius, $theta, $z);

Convert from polar to cartesian coordinates.

my ($radius, $theta, $z) = cart_to_pol($x, $y, $z);

print_line(\@line, $message);

Averages the x and y coordinates of a list of points.

my ($x, $y) = point_avg(@points);

Given a pair of endpoints and an angle (in radians), returns an arc with center, radius, and start/end angles.

my %arc = arc_2pt(\@pts, $angle);

syntax highlighting: