Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

Just tangent?? I don't need no stinking tangent!

Since you beat me to the subject of vector algebra I'll skip much of my introduction about how trigonometry sucks for this. Why would anyone want to approximate a bunch of transcendental functions just to approximate another bunch of transcendental functions that are their inverses? Plus you have to special-case horizontal (or vertical, depending) lines.

With vector algebra you only need to do a few simple subtractions, multiplications, additions, exactly one division (where the denominator is never 0), and take exactly one square root.

I'll call our points A and B. Let's let V = ( xv, yv ) be the vector from A to B. Then -V = ( -xv, -yv ) points the other direction. But ( -yv, xv ) and ( yv, -xv ) point perpendicular. So scale these to be the right length and add them to A and B and you get the 4 points of your box that defines your "think line".

And you can do that without having to repeat yourself much if you let the code do the repeating for you:

#!/usr/bin/perl -w use strict; # This takes two 2-dimensional points (A and B) # and a width, and returns 4 points that are the # counter-clockwise perimeter of a "thick line" # (box) of the specified width around the line. sub line2box { my $w= pop @_; die 'Usage: line2box($ax,$ay,$bx,$by,$width)' if $w <= 0 || 4 != @_; # We just keep our 4 coordinates in a single array # so we don't have to repeat ourselves much below. $w /= 2; # Length of offset vector is $width/2 my @d; # Differences between X and Y coord.s my $l= 0; for( 0, 1 ) { my $d= $_[$_] - $_[2+$_]; $l += $d*$d; push @d, $d; } # Now $l is length**2, so we want to scale our # perpendicular vectors by $width / $length so: $l= sqrt( $w*$w / $l ); $_ *= $l for @d; my @box; my @s= ( -1, 1 ); # Sign to apply (- or +) for my $s ( 0, 1 ) { # Index into @s # $p==0 for A, $p==1 for B for my $p ( $s, !$s ) { # Which point for my $c ( 0, 1 ) { # Which coordinate # Push the selected coordinate push @box, $_[2*$p+$c] + $s[$s^$c]*$d[!$c]; } } } return @box; } while( <DATA> ) { last if !/\S/; my @line= split ' '; $line[-1] **= 0.5; my @box= line2box( @line ); printf qq[A line from A( %5.1f, %5.1f )$/] . qq[ to B( %5.1f, %5.1f )$/] . qq[of width sqrt( %5.1f )$/] . qq[is a box, counter-clock-wise:$/] . qq[ W( %5.1f, %5.1f )$/] . qq[ X( %5.1f, %5.1f )$/] . qq[ Y( %5.1f, %5.1f )$/] . qq[ Z( %5.1f, %5.1f )$/] . $/ , @line[0..3], $line[4]**2, , @box; }

And here is some sample input, sample output, and some ASCII-art drawings thrown in to make sense of the numbers.

__END__ 1 0 1 5 4 1 1 6 1 16 -1 -2 2 1 8 A line from A( 1.0, 0.0 ) to B( 1.0, 5.0 ) of width sqrt( 4.0 ) is a box, counter-clock-wise: W( 2.0, 0.0 ) X( 2.0, 5.0 ) Y( 0.0, 5.0 ) Z( 0.0, 0.0 ) w=2 |<--->| | (Y)(B)(X) | # 4+ # | # 3+ # | # 2+ # | # 1+ # | # --+--+-(Z)(A)(W)-+-- -2 -1 0 1 2 A line from A( 1.0, 1.0 ) to B( 6.0, 1.0 ) of width sqrt( 16.0 ) is a box, counter-clock-wise: W( 1.0, -1.0 ) X( 6.0, -1.0 ) Y( 6.0, 3.0 ) Z( 1.0, 3.0 ) | 4+ | 3+ (Z) (Y) --- | ^ 2+ | | | 1+ (A)############(B) w=4 | | --+--+--+--+--+--+--+--+--+- | -1 0 1 2 3 4 5 6 7 v -1+ (W) (X) --- | -2+ | A line from A( -1.0, -2.0 ) to B( 2.0, 1.0 ) of width sqrt( 8.0 ) is a box, counter-clock-wise: W( 0.0, -3.0 ) X( 3.0, 0.0 ) Y( 1.0, 2.0 ) Z( -2.0, -1.0 ) | 3+ / | \ 2+ (Y) w=2*(2**.5) | \ 1+ (B) / | // --+--+--+--+--+--+-(X)-+-- -3 -2 -1 0//1 2 3 4 (Z) -1+ //| (A) -2 | -3(W) | -4+ |

Note that the line:

for my $p ( $s, !$s ) { # Which point

is a tricky way of saying "the first time through (using a negative sign) do A first then B; the second time through (using a positive sign) do B first then A". This gives us the dots in a perimeter order (so you could just connect them if you wanted the outline of the thick line).

And I didn't have to memorize any rules about cos() vs. sin() or even worry about which coordinate was x or y. I just do all of the combinations and I get all of the points needed.

- tye        


In reply to Re^2: Code refactoring: simple trig, but it's been so long. (no trig!) by tye
in thread Code refactoring: simple trig, but it's been so long. by revdiablo

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (8)
As of 2024-04-16 10:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found