2

球上に 10 個の点 (ランダムに分布) があり、1 つの点が北極にくるようにシステム全体を回転させたいとします。c ++を使用してこれを行うにはどうすればよいですか?

私は3D回転行列を見てそれについて行きました:

http://en.wikipedia.org/wiki/Rotation_matrix

y 成分がゼロになるまで x 軸を中心にポイントを回転させ、次に x 成分がゼロになるまで y 軸を中心に回転させます。これで、問題の点は北極か南極のどちらかになるはずですよね?

私のコードは次のようになります。

#include <stdio.h> 
#include <string.h>
#include <math.h>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <time.h>
#include <stdlib.h>
#include <sstream>
using namespace std;
#define PI 3.14159265358979323846

int main()
{

  int a,b,c,f,i,j,k,m,n,s;
  double p,Time,Averagetime,Energy,energy,Distance,Length,DotProdForce,Forcemagnitude,
         ForceMagnitude[101],Force[101][4],E[1000001],En[501],x[101][4],y[101][4],
         Dist[101][101],Epsilon,z[101],theta,phi;

    /*  set the number of points */
    n=10;

    /* check that there are no more than 100 points */
    if(n>100){
      cout << n << " is too many points for me :-( \n";
      exit(0);
    }

    /* reset the random number generator */
    srand((unsigned)time(0));  

    for (i=1;i<=n;i++){
      x[i][1]=((rand()*1.0)/(1.0*RAND_MAX)-0.5)*2.0;
      x[i][2]=((rand()*1.0)/(1.0*RAND_MAX)-0.5)*2.0;
      x[i][3]=((rand()*1.0)/(1.0*RAND_MAX)-0.5)*2.0;

      Length=sqrt(pow(x[i][1],2)+pow(x[i][2],2)+pow(x[i][3],2));

      for (k=1;k<=3;k++){
        x[i][k]=x[i][k]/Length;
      }
    }

    /* calculate the energy */
    Energy=0.0;

    for(i=1;i<=n;i++){
      for(j=i+1;j<=n;j++){
        Distance=sqrt(pow(x[i][1]-x[j][1],2)+pow(x[i][2]-x[j][2],2)
                    +pow(x[i][3]-x[j][3],2));

        Energy=Energy+1.0/Distance;
      }
    }

   cout << fixed << setprecision(10) << "energy=" << Energy << "\n";  

  /* Save Values so far */

  for(i=1;i<=n;i++){
    for(j=1;j<=3;j++){
      y[i][j]=x[i][j];
    }
  }

  /* Choose each point in turn and make it the north pole note this is what the while loop os for, but have set it to a<2 to just look at first point */

  a=1;
  b=0;
  c=0;

  while(a<2){

  /* Find theta and phi to rotate points by */

  cout << fixed << setprecision(5) << "x[" << a << "][1]=" << x[a][1] << 
  " x[" << a << "][2]=" << x[a][2] << " x[" << a << "][3]=" << x[a][3] << "\n";

  theta=x[a][2]/x[a][3];
  theta=b*PI+atan(theta);

  /* Rotate Points by theta around x axis and then by phi around y axis */

  for(i=1;i<=n;i++){
    x[i][1]=x[i][1];
    x[i][2]=x[i][2]*cos(theta)-x[i][3]*sin(theta);
    x[i][3]=x[i][2]*sin(theta)+x[i][3]*cos(theta);
  }

  phi=x[a][1]/x[a][3];
  phi=c*PI+atan(phi);

  for(i=1;i<=n;i++){
    x[i][1]=x[i][1]*cos(phi)-x[i][3]*sin(phi);
    x[i][2]=x[i][2];
    x[i][3]=x[i][1]*sin(phi)+x[i][3]*cos(phi);
  }

  cout << fixed << setprecision(5) << "x[" << a << "][1]=" << x[a][1] << 
  " x[" << a << "][2]=" << x[a][2] << " x[" << a << "][3]=" << x[a][3] << "\n";

   if(x[a][3]==1.0 && x[a][2]==x[a][3]==0)
    a=a+1;
  else if(b==0 && c==0)
    for(i=1;i<=n;i++){
      for(j=1;j<=3;j++){
        x[i][j]=y[i][j];
        c=1;
      }
    }
  else if(b==0 && c==1)
    for(i=1;i<=n;i++){
      for(j=1;j<=3;j++){
        x[i][j]=y[i][j];
        b=1;
        c=0;
      }
    }
  else if(b==1 && c==0)
    for(i=1;i<=n;i++){
      for(j=1;j<=3;j++){
        x[i][j]=y[i][j];
        c=1;
      }
    }
  else if(b==1 && c==1)
    break;

  }

  energy=0.0;

  for(i=1;i<=n;i++){
    for(j=i+1;j<=n;j++){

      Distance=sqrt(pow(x[i][1]-x[j][1],2)+pow(x[i][2]-x[j][2],2)
                    +pow(x[i][3]-x[j][3],2));
      energy=energy+1.0/Distance;
    }
  }  

  cout << fixed << setprecision(10) << "ENERGY=" << energy << "\n";  
  cout << fixed << setprecision(5) << "x[" << a << "][1]=" << x[a][1] << 
  " x[" << a << "][2]=" << x[a][2] << " x[" << a << "][3]=" << x[a][3] << "\n";

  /* Output to help with gnuin.txt */
  ofstream File4 ("mypoints");
  for(i=1;i<=n;i++){
    File4 << x[i][1] << " " <<   x[i][2] << " " << x[i][3] << "\n";
  }
  File4.close(); 

  return 0;

}

わかりましたので、if ステートメント (103 行目) は決して機能しないため、double に等しいという条件を実際に持つべきではありませんが、後で間接比較 (いくつかのイプシロンのもの) を使用してそれを整理できます)。私の本当の質問は、回転がすべての点に作用しているにもかかわらず、球から点を奪うのはなぜですか? (ご覧のとおり、38 行目ですべての値が単位球上になるように値が正規化されています)。

注: b、c は、ポイントが北極または南極にあるかどうかを確認するためのものです。

4

1 に答える 1

4

ローテーション コードに問題があります。例えば:

x[i][1]=x[i][1];
x[i][2]=x[i][2]*cos(theta)-x[i][3]*sin(theta);
x[i][3]=x[i][2]*sin(theta)+x[i][3]*cos(theta);

2 行目で変更x[i][2]し、3 行目で使用します。参照が完了する前に値を変更しないように、中間結果には一時ストレージを使用する必要があります。

最初の行はかなり冗長ですが、残りは次のようになります。

double new_y, new_z;
new_y=x[i][2]*cos(theta)-x[i][3]*sin(theta);
new_z=x[i][2]*sin(theta)+x[i][3]*cos(theta);
x[i][2] = new_y;
x[i][3] = new_z;

(そして明らかに、そのような計算を実行する場所でそれを行います)

球を方向付けるより良い方法は、「ルックアット」行列と同じ方法で変換行列を計算することです。ルックアット マトリックスでは、フレームを回転させて、ベクトルを z 軸に揃えます。あなたの場合、おそらくy軸に沿って整列させたいと思うでしょうが、原則は同じです。

また、配列の 0 番目の要素を無視しているようだとコメントしたいと思います... IMHO これは悪い習慣です。配列がゼロから始まるという事実に慣れる必要があります。遅かれ早かれ、インデックス作成が間違っているか、他の誰かのコードに接続する必要があります。

于 2013-01-22T20:33:10.247 に答える