2

私は(2Dポイントとして)3D球体を歩き回る必要があるプロジェクトに取り組んでいます。極歪みなしでこれを達成する方法を理解するのに苦労しています。基本的には、前進、後進、左折、右折、および左折、右折が必要です。これを球座標で機能させようとしましたが、関数が正しくないようです。これを機能させるにはどうすればよいですか?(p5.js ライブラリを使用して JavaScript で作成しています)

現在、x 変数と y 変数をそれぞれ球面空間の phi と theta にマッピングしようとしています。ただし、機能していないようです。正しく実装された場合、ポイントが大円に移動するかどうかはわかりません。

また、角度変数を使用して x と y を (cos(A), sin(A)) だけ移動していますが、これが機能しているかどうかはわかりません。

私がしなければならないことは、大円航法に関連していると思いますが、その背後にある数学がわかりません。

現在のバージョンへのリンク: https://editor.p5js.org/hpestock/sketches/FXtn82-0k

現在のコードは次のようになります

var X,Y,Z;
X=0;
Y=0;
Z=0;

var A=0;

var scaler = 100;

var MOVE_FORWARD = true;
var MOVE_BACKWARD= false;
var MOVE_LEFT    = false;
var MOVE_RIGHT   = false;
var TURN_LEFT    = false;
var TURN_RIGHT   = false;

//var i=0;
var x = 0;
var y = 0;

function setup() {
  createCanvas(400, 400, WEBGL);
  x= 0;
  y= 0;
  A= 0;
  background(220);
}

function keyPressed(){
  if(key == "w"){
    MOVE_FORWARD = true;
  }else if(key == "ArrowLeft"){
    TURN_LEFT = true;
  }else if(key == "ArrowRight"){
    TURN_RIGHT = true;
  }
}

function keyReleased(){
  if(key == "w"){
    MOVE_FORWARD = false;
  }else if(key == "ArrowLeft"){
    TURN_LEFT = false;       
  }else if(key == "ArrowRight"){
    TURN_RIGHT = false;
  }
}

function draw() {
  
  if(MOVE_FORWARD){
    x+=0.005*cos(A);
    y+=0.005*sin(A);
  }
  if(TURN_LEFT){
    A+=PI/64;
  }
  if(TURN_RIGHT){
    A-=PI/64;
  }
  
  var xyz = Sph(1,y,x);
  X=xyz[0];
  Y=xyz[1];
  Z=xyz[2];
  background(220);
  sphere(scaler);
  push();
  translate(X*scaler,Y*scaler,Z*scaler);
  sphere(5);
  pop();
  
  /*i+=PI/32;
  if(i>2*PI){
     i=0;
     }*/
}

function Move(a,d){
  //
}

function Sph(p,t,h){
  //p = radius
  //t (theta) = 2d rotation
  //h (phi) = 3d roation
  return ([p*cos(h)*cos(t),p*cos(h)*sin(t),p*sin(h)]);
  
  //x=ρsinφcosθ,y=ρsinφsinθ, and z=ρcosφ
}
4

2 に答える 2

1

私はjavascriptを知りませんが、次の関数を実装することができます(私はPythonで実装しました。うまくいけば、それらの背後にある数学的/幾何学的ロジックを読み取ることができます)。与えられた角度 ds のステップに沿って大円に沿って移動し、運動の方向を変更します。運動は(半径1の)単位球上にあると仮定しています。そうでない場合は、コードを適切な半径にスケーリングする必要があります。

import numpy as np
import math

def direct(r, a):
'''
given position-vector r on the unit sphere and initial angle a, 
measured from the meridian, i.e. direction north being a = 0,
the result is the unit vector t pointing in that direction 
'''
  e_z = np.array([0,0,1]) 
  u = np.cross(e_z, r)
  u = u / math.sqrt(u.dot(u))
  v = np.cross(r, u)
  t = math.cos(a) * v + math.sin(a) * u
  return r, t

def move(r, t, ds):
'''
given unit position-vector r and unit direction vector t on the unit sphere, 
make a step of arclength ds radians from point r in the direction of t along
the great circle that passes through r and tangent to t. The result is the
new position r_ and the new direction vector t_ still tangent to the same
great circle.
'''
  co = math.cos(ds)
  cs = math.sin(ds) 
  r_ =  co * r + si * t
  t_ = -si * r + cs * t
  return t_, t_

def redirect(r, t, da):

'''
given unit position-vector r and unit direction vector t on the unit sphere, 
rotate the vector t at an angle da. 
The result is the new direction vector t_

when da > 0 redirect right
when da < 0 redirect left
'''
  rot_axis = np.cross(r, t)
  t_ = math.cos(da) * t - math.sin(da) * rot_axis
  return r, t_
于 2021-11-12T04:17:48.127 に答える
1

極座標でこれを行うための数学についてはわかりませんが、位置と向きを 3 次元デカルト ベクトルのペアとして追跡し、Rodrigues の回転式を使用して (位置を回転させて) 前方に移動し、(軸を回転させます)。

// position vector
let pos;
// axis of rotation
let axis;

let scaler = 150;

function setup() {
  createCanvas(400, 400, WEBGL);
  background(220);
  pos = createVector(1, 0, 0);
  axis = createVector(0, 1, 0);
  fill('red');
  noStroke();
}

function draw() {
  if (keyIsDown(87) || keyIsDown(UP_ARROW)) {
    // move "forward"
    rotateVector(pos, axis, PI / 64);
  }
  if (keyIsDown(LEFT_ARROW)) {
    // turn left
    rotateVector(axis, pos, -PI / 64);
  }
  if (keyIsDown(RIGHT_ARROW)) {
    // turn right
    rotateVector(axis, pos, PI / 64);
  }

  ambientLight(100);
  directionalLight(200, 200, 200, 1, 1, -1);

  push();
  translate(pos.x * scaler, pos.y * scaler, pos.z * scaler);
  sphere(5);
  pop();
}

function rotateVector(v, axis, angle) {
  // v * cos(θ) + (axis ✕ v) * sin + axis * (axis · v) * (1 - cos)
  return v.mult(cos(angle))
    .add(axis.copy().cross(v).mult(sin(angle)))
    .add(axis.copy().mult(axis.dot(v) * (1 - cos(angle))));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

于 2021-11-08T19:54:05.000 に答える