Найти ближайшую точку из file1 в file2, shell skript

#bash #awk #coordinates #nearest-neighbor

#bash #awk #координаты #ближайший сосед

Вопрос:

У меня есть 2 файла:

file1
-3241.42 633.261 1210.53
-1110.89 735.349 836.635
(это точки, которые я ищу, с координатами x, y, z)
file2
 2014124 -2277.576 742.75 962.5816 0 0
 2036599 -3236.882 638.748 1207.804 0 0
 2036600 -3242.417 635.2612 1212.527 0 0
 2036601 -3248.006 631.6553 1217.297 0 0
 2095885 -1141.905 737.7666 843.3465 0 0
 2095886 -1111.889 738.3486 833.6354 0 0
 2095887 -1172.227 737.4004 853.9965 0 0
 2477149 -3060.679 488.6802 1367.816 0 0
 2477150 -3068.369 489.6621 1365.769 0 0
и так далее
(это точки из моей модели с идентификатором, x, y, z, 0, 0)

Я ищу такой результат: (найдите идентификаторы точек с ближайшими координатами)

 Output
2036600 ,  xyz= -3242.42, 635.261, 1212.53, dist= 3.00
2095886 ,  xyz= -1111.89, 738.349, 833.635, dist= 4.36
 

Мой алгоритм будет выглядеть следующим образом:

 For each line in file1, catch x1,y1,z1
  Search in file2 the nearest point, that mean dist = sqrt((x1-x2)**2 (y1-y2)**2 (z1-z2)**2) is minimum
Display the result with pointID, xyz = x2, y2, z2, dist= dist
 

Я попытался адаптировать скрипт, найденный здесь, но он выдает много строк

 #!/bin/bash
(($#!=2))amp;amp; { echo "Usage $0 1st_file 2nd_file"; exit 1; }
awk '
 BEGIN {p=fx=0; fn=""; maxd=1.1e11;}
 $0~"[^0-9. t]" || NF!=4 amp;amp; NF!=3 {next;}          # skip no data lines
 fn!=FILENAME {fx  ; fn=FILENAME;}                  # fx: which file
 fx==1 { if(NF!=3){printf("Change the series of two input filesn"); exit 1;}
         x1[p]=$1; y1[p]=$2; z1[p]=$3;next;}      # save the columns of first file
 fx==2 { mv=maxd; mp=0;                             # search minimal distance
           for(i=0; i<p; i  ){
              dx=x1[i]-$2; dy=y1[i]-$3; dz=z1[i]-$4; dist=sqrt(dx*dx dy*dy dz*dz);
              if(dd<mv){mv=dd; mp=i;}               # min value amp; min place
           }
           printf("= %6.2f %6.2f =n", $1, x1[mp], y1[mp], z1[mp], dist);
       }
' file1.dat file2.dat 
 

Большое вам спасибо!

Комментарии:

1. Привет @Leo, пожалуйста, покажите свои собственные усилия и как это не сработало. В общем, чем меньше кода вы вставляете, тем больше вероятность, что кто-то серьезно посмотрит и ответит.

Ответ №1:

 $ cat tst.awk
BEGIN { OFS=", " }
NR==FNR {
    points[NR] = $0
    next
}
{
    min = 0
    for (i in points) {
        split(points[i],coords)

        dist = ($1 - coords[2])^2   
               ($2 - coords[3])^2   
               ($3 - coords[4])^2

        if ( (i == 1) || (dist <= min) ) {
            min = dist
            point = points[i]
        }
    }
    split(point,p)
    print p[1] " ", "xyz= " p[2], p[3], p[4], "dist= " sqrt(min)
}
 
 $ awk -f tst.awk file2 file1
2036600 , xyz= -3242.417, 635.2612, 1212.527, dist= 2.99713
2095886 , xyz= -1111.889, 738.3486, 833.6354, dist= 4.35812
 

Комментарии:

1. впечатляет! Большое вам спасибо

2. очень чисто. Одно предложение: вы можете dist^2 вместо этого вычислить и просто использовать единицу sqrt в конце для минимального значения.