Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations wOOdy-Soft on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

distance between 2 points 2

Status
Not open for further replies.

Alfio75

Programmer
Oct 25, 2005
25
MX
Hello guys.
I got a file and it has numbers on rows

x1 y1 z1
x2 y2 z2

what i need is to read this 2 point ( row number one and row number 2) and calculate the distance between them using the next expression:

d=square root( (x2-x1)**2 +(y2-y1)**2 +(z2-z1)**2 )

Think about a lot of rows and a lot of comparations

for example:

point1 ----------point2------point3

i need to comparate distance between point 1 and point 2
but distance between point1 and point 3 too
I mean
p1 with p2
p1 with p3
p3 with point p1

and finally I want to print just those distance less than VALUE.

Thanks in advance

 
Here, try this:
Code:
my @points = map {[split]} <DATA>;
my $min_dist = 10;

foreach my $point (0..$#points) {
    my $comparePoint = $point == $#points ? 0 : $point+1;
    my $dist = calc_distance(\@{$points[$point]}, \@{$points[$comparePoint]});
    if ($dist < $min_dist) {
        print "Dist from P$point to P$comparePoint: $dist\n";
    }
}

sub calc_distance {
    my ($aref1, $aref2) = @_;
    my $x = ($aref2->[0] - $aref1->[0])**2;
    my $y = ($aref2->[1] - $aref1->[1])**2;
    my $z = ($aref2->[2] - $aref1->[2])**2;
    return sqrt($x+$y+$z);
}

__DATA__
1 2 3
6 5 4
7 8 9
 
The code I posted will do what you want (p0 to p1, p1 to p2, p2 to p0) but what are you expecting to happen with a fourth point (p3)? Will you only ever have 3 points at any time?

With a fourth point, the code above would compute the distances from:
p0->p1, p1->p2, p2->p3, p3->p0

Or are you expecting something more like:
p0->p1, p0->p2, p0->p3,
p1->p2, p1->p3,
p2->p3
 
Hello again. I'm really expecting 200 rows to be compared.
In fortran i did 2 nested cycles and i put a conditional to do that.

that is a kind of:

for 10 i=1,nrows
for 20 j=1, nrows-1

distance(i,j)= square(x**2+y**2+z**2)
if (distance(i,j).LE.VALUE) then
print (*,30) value
20 continue
30 format(f10.3)
10 continue


I meant, it's necesary to compare
1 with 2 ,1 with 3, 1 with 4.....1 with N-1
2 w 2, 2 w 3, 2 w 4...............2 w N-1
.
..
N-1 w 1


Do u copy me?
 
Aside from not needing the comparison 2w2, yeah, I understand. Try this instead:
Code:
my @points = map {[split]} <DATA>;
my $min_dist = 10;
dist_between_points(0..$#points);

sub dist_between_points {
    my $point = shift;
    if (@_) {
        foreach (@_) {
            my $dist = calc_distance(\@{$points[$point]}, \@{$points[$_]});
            print("p$point to p", $_, ": $dist\n") if ($dist < $min_dist);
        }
        &dist_between_points;
    }    
}

sub calc_distance {
    my ($aref1, $aref2) = @_;
    my $x = ($aref2->[0] - $aref1->[0])**2;
    my $y = ($aref2->[1] - $aref1->[1])**2;
    my $z = ($aref2->[2] - $aref1->[2])**2;
    return sqrt($x+$y+$z);
}

__DATA__
1 2 3
6 5 4
7 8 9
9 1 5
 
I use ur code and i get something like that:
How could i avoid to get a lot of lines without sense?

Now imagine that u get blocks of data like

123
456
789

10 11 12
13 14 15
16 17 18

I meant, blocks of 3 rows or more, and i need to print that information of each block to a file
example first block to 1.dat
second block to 2.dat, etc

********************************
#!/usr/bin/perl -w
#use strict;

my @points = map {[split]} <DATA>;
my $min_dist = 10;
dist_between_points(0..$#points);

sub dist_between_points {
my $point = shift;
if (@_) {
foreach (@_) {
my $dist = calc_distance(\@{$points[$point]}, \@{$points[$_]});
print("p$point to p", $_, ": $dist\n") if ($dist < $min_dist);
}
&dist_between_points;
}
}

sub calc_distance {
my ($aref1, $aref2) = @_;
my $x = ($aref2->[0] - $aref1->[0])**2;
my $y = ($aref2->[1] - $aref1->[1])**2;
my $z = ($aref2->[2] - $aref1->[2])**2;
return sqrt($x+$y+$z);
}

__DATA__
5.04786152982032E+00 4.23000449311482E+00 8.04732158465680E+00
8.06191440232750E+00 5.82244841863038E+00 4.95787603533274E+00
5.04638324236482E+00 8.33705252525774E+00 7.32433413587005E+00
2.04108475715077E+00 5.82001901588952E+00 5.05415800574768E+00
5.13925614436763E+00 8.40867652716315E+00 2.75714159286964E+00
2.61800142894251E+00 1.77738175002289E+00 5.02054486805876E+00
4.94928280233908E+00 4.07302530110812E+00 2.01973663276942E+00
7.22636291779700E+00 1.72292369993206E+00 5.01056990979596E+00

****************************
The last it's the code used.

p7 to p8: 8.96072530080305
Use of uninitialized value in subtraction (-) at distance.pl line 21, <DATA> line 10.
Use of uninitialized value in subtraction (-) at distance.pl line 22, <DATA> line 10.
Use of uninitialized value in subtraction (-) at distance.pl line 23, <DATA> line 10.
p7 to p9: 8.96072530080305
Use of uninitialized value in subtraction (-) at distance.pl line 21, <DATA> line 10.
Use of uninitialized value in subtraction (-) at distance.pl line 21, <DATA> line 10.
Use of uninitialized value in subtraction (-) at distance.pl line 22, <DATA> line 10.
Use of uninitialized value in subtraction (-) at distance.pl line 22, <DATA> line 10.
Use of uninitialized value in subtraction (-) at distance.pl line 23, <DATA> line 10.
Use of uninitialized value in subtraction (-) at distance.pl line 23, <DATA> line 10.
 
When I run the data you posted, I get the output just fine:
Code:
p0 to p1: 4.60055063839302
p0 to p2: 4.17019862533741
p0 to p3: 4.53077045913911
p0 to p4: 6.74208107999385
p0 to p5: 4.59140019187064
p0 to p6: 6.03043452700169
p0 to p7: 4.50035366785015
p1 to p2: 4.58440682437452
p1 to p3: 6.02159993158493
p1 to p4: 4.48037266401238
p1 to p5: 6.78252756705522
p1 to p6: 4.62402636997919
p1 to p7: 4.18413979772732
p2 to p3: 4.53000842541046
p2 to p4: 4.56869818421111
p2 to p5: 7.36435767068065
p2 to p6: 6.80662260843392
p2 to p7: 7.33842737902077
p3 to p4: 4.64500786396253
p3 to p5: 4.08373343309651
p3 to p6: 4.55162783829149
p3 to p7: 6.60872147646003
p4 to p5: 7.4467301648118
p4 to p6: 4.40201402767579
p4 to p7: 7.3575297981081
p5 to p6: 4.43956103917553
p5 to p7: 4.60869404397484
p6 to p7: 4.43318791379673

The line 'my @points = map {[split]} <DATA>;' is there to simplify reading the data into an array of arrays, you might need to tweak the input a bit to skip blank lines and verify the data is good prior to adding it to the array.
 
Hello rharsh.
ok ur code is working...now i got another question.
In the last code u can know distances for 1 data set of 8 rows right?
What should i do to be able to do the same for more than 1 data block ?
Example:
1 0.266E+01 0.229E+01 0.384E+01
2 0.383E+01 0.301E+01 0.264E+01
1 0.266E+01 0.408E+01 0.357E+01
1 0.146E+01 0.301E+01 0.266E+01
2 0.267E+01 0.409E+01 0.174E+01
1 0.172E+01 0.123E+01 0.264E+01
2 0.264E+01 0.227E+01 0.147E+01
1 0.355E+01 0.123E+01 0.264E+01

2 0.266E+01 0.228E+01 0.393E+01
1 0.393E+01 0.302E+01 0.263E+01
1 0.267E+01 0.416E+01 0.364E+01
2 0.137E+01 0.302E+01 0.266E+01
1 0.268E+01 0.418E+01 0.167E+01
2 0.163E+01 0.117E+01 0.264E+01
1 0.263E+01 0.224E+01 0.138E+01
1 0.361E+01 0.116E+01 0.264E+01

1 0.267E+01 0.226E+01 0.409E+01
2 0.408E+01 0.305E+01 0.263E+01
2 0.267E+01 0.428E+01 0.375E+01
2 0.124E+01 0.305E+01 0.267E+01
1 0.270E+01 0.431E+01 0.157E+01
1 0.152E+01 0.107E+01 0.265E+01
1 0.262E+01 0.220E+01 0.123E+01
1 0.371E+01 0.105E+01 0.265E+01

Where the first column is just a label to "red " and "green" points.

So what i want to get is a code where i can print distance between green and red points and to know when i'm getting each other and maybe give a radius to green and to red
for example is the next
points.
p0 to p1: 4.60055063839302 where p0 is red
p0 to p2: 4.17019862533741 where p2 is green
p0 to p3: 4.53077045913911
p0 to p4: 6.74208107999385
p0 to p5: 4.59140019187064

 
To run the code on multiple data sets, just read in one data set at a time, put the contents in @points, and run dist_between_points(). Make sure you empty @points (ex. @points = ();) before you read in the new data set.

For the red/green points question, I'm not sure what you're looking for. Do you want all the red points compared against all the green points? For example, if (p0,p1,p2,p3,p4) are red and (p5,p6,p7) are green, are you expecting:
p0-p5,p0-p6,p0-p7,
p1-p5,p1-p6,p1-p7,
p2-p5,p2-p6,p1-p7, etc... or do you want the comparisons done differently?
 
Hello again.
What i really want to get is comparations between all the points, same way ur last code did it.
but i need to print the kind of colors for example, just to know if i'm comparing red with red and red with green. That's because when i print those to a file i want to identify them assign to each a radius.So red radius is less than green radius for example

I can't copy and paste all the time...because i got 600 data blocks!.. that will be a lot of work!. So what i need is to be able to paste one time all the data blocks and do just i run.


 
I think i can assing radius if i can split the rows and if the field number one is 1 then i got a red point.I got the idea but i'm a newbie in perl
 
See if this helps you - I put a comment in for you, but just to reiterate, the color index (1 or 2) is actually going to be the last element in the array, not the first (the first element is actually field 0, not field 1). I did that so calc_distance() didn't need to be changed.
Code:
my ($min_dist,$set_num) = (10,0);
my %colors = (1 => 'Red', 2 => 'Green');
my @points;

$/ = "\n\n";  # Assumes double space between data sets
while (my $dataset = <DATA>) {
    print "Data Set Number: ", ++$set_num, "\n";
    @points = map {[(split)[1..3,0]]} split(/\n/, $dataset); # Put Color Index at end of array
    dist_between_points(0..$#points);
}

sub dist_between_points {
    my $point = shift;
    if (@_) {
        foreach (@_) {
            my ($pointA, $pointB) = (\@{$points[$point]}, \@{$points[$_]});
            my $dist = calc_distance($pointA,$pointB);
            if ($dist < $min_dist) {
                printf "%-9s to %-9s: %1.3e\n", "p$point($colors{$pointA->[-1]})",
                        "p$_($colors{$pointB->[-1]})",$dist;
            }
        }
        &dist_between_points;
    }    
}
For calculating your radius, all the values are already split up. Within each data set, $points[0][0] would be the x-coordinate for point 0, $points[5][1] would be the y-coordinate for point 5 and so on.
 
thanks rharsh let me try something and tomorrow U'll get one question more
 
#!/usr/bin/perl
#use strict;

my $min_dist = 2;
my @points = map {[split]} <DATA>;

dist_between_points(0..$#points);


#{[(split)[1..3,0]]}

#******************************************************
sub dist_between_points {

my $point = shift;

if (@_) {
foreach (@_) {

my $dist = calc_distance(\@{$points[$point]}, \@{$points[$_]});


if ($dist < $min_dist){
print "<" ,join(',',@{$points[$point]} ) , ">,";
print "<",join(',',@{$points[$_]}),">","\n";

fi}

}
&dist_between_points;
}
}

#*********************************************************

sub calc_distance {
my ($aref1, $aref2) = @_;
my $x = ($aref2->[0] - $aref1->[0])**2;
my $y = ($aref2->[1] - $aref1->[1])**2;
my $z = ($aref2->[2] - $aref1->[2])**2;
return sqrt($x+$y+$z);
}

__DATA__
0.266E+01 0.229E+01 0.384E+01
0.383E+01 0.301E+01 0.264E+01
0.266E+01 0.408E+01 0.357E+01
0.146E+01 0.301E+01 0.266E+01
0.267E+01 0.409E+01 0.174E+01
0.172E+01 0.123E+01 0.264E+01
0.264E+01 0.227E+01 0.1E+01
0.355E+01 0.123E+01 0.264E+01

0.266E+01 0.228E+01 0.393E+01
0.393E+01 0.302E+01 0.263E+01
0.267E+01 0.416E+01 0.364E+01
0.137E+01 0.302E+01 0.266E+01
0.268E+01 0.418E+01 0.167E+01
0.163E+01 0.117E+01 0.264E+01
0.263E+01 0.224E+01 0.138E+01
0.361E+01 0.116E+01 0.264E+01

Hello..What i would like to get is to add first, every data block to files named 1.dat, 2.dat, 3.dat?
So after a run i'll get

file: 1.dat with all the comparations of de first block
file: 2.dat with the second block comparations

How about if i got all those files already and i just wanna concatenate this to the end of each other?
 
You should be able to print to each file by using code similar to:
Code:
while (my $dataset = <DATA>) {
    $set_num++;
    open (FILE, '>' . sprintf("%03d", $set_num) . '.dat') or die "Cannot create file $set_num\n$!\n";
    select FILE;
    print "Data Set Number: $set_num\n";
    @points = map {[(split)[1..3,0]]} split(/\n/, $dataset); # Put Color Index at end of array
    dist_between_points(0..$#points);
    select STDOUT;
    close FILE;
}
As far as reading each file and adding them to one long file, you probably have most the code you need in your other post. Also take a look at perldoc -f open and it should give you a good place to start. Give it a shot and, if you have questions, post them and I'm sure everyone will be glad to help.
 
no rharsh , what i need is to add for example the 1.dat to an existent 1.dat , the 2.dat to another old 2.dat etc.
 
To overwrite/create a new file for output, you use:
Code:
open FH, "> file.txt";
To append, use:
Code:
open FH, ">> file.txt";
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top