ジューコフスキー翼の座標を出す関数&plotlyで2D描画 & Three.jsで3D描画

# ジューコフスキー翼
ジューコフスキー翼というのを使えばそれっぽい翼型を描けます。とりあえずなんでもいいから翼を描きたいという方はお試しください。

参考URL ＦＮの高校物理
http://fnorio.com/0116two_dimensional_wing_theory0/two_dimensional_wing_theory0.html

![Imgur](https://i.imgur.com/cy3pv78.png)

# 座標を出す関数
下のzukofsky関数の3つの引数x0, y0, cに数字を入れると翼型を書くための関数zetaが返ってきます。zetaに0～2πの値を入れると翼面上の座標がx,yを含んだオブジェクトで帰ってきます。
x0で翼の太さ、y0で翼の反り具合、cで翼の長さを変えられます。

```javascript
const zukofsky = (x0, y0, c) => {

  const b = c/4 
  const a = Math.sqrt((b-x0)**2+y0**2)
  
  const z = t =>{
    return {
      x: a*Math.cos(t)+x0,
      y: a*Math.sin(t)+y0,
    }
  }
  
  const invZ = t =>{
    const w = (a*Math.cos(t)+x0)**2+(a*Math.sin(t)+y0)**2
    return {
      x: (a*Math.cos(t)+x0)/w, 
      y: -(a*Math.sin(t)+y0)/w, 
    }
  }
  
  const zeta = t => {
    const temp1 = z(t)
    const temp2 = invZ(t)
    const temp3 = {x: 0, y:0}
    temp3.x = temp1.x + b**2*temp2.x
    temp3.y = temp1.y + b**2*temp2.y
    return temp3 
  }
  return zeta
}

const x0 = -0.05
const y0 = 0.1
const c = 1
const wing1 = zukofsky(x0, y0, c)

```

# plotlyで2D描画
plotly.jsを使って、素直に描画します。翼面上の点を100分割します。

```javascript
const N = 100 
const xyList = [...Array(N)].map((k,i)=>i).reduce((pre,i)=>{
  const temp = wing1(i*2*Math.PI/N)
  pre.x.push(temp.x)
  pre.y.push(temp.y)
  return pre 
},{x:[], y:[]})

const trace1 = {
  x: xyList.x,
  y: xyList.y,
  type: "scatter",
  model: "lines" 
}

const data = [trace1]
const layout = {
 height: 500, 
 width: 500, 
 xaxis:{
   range: [-0.6, 0.6]
 },
 yaxis:{
   range: [-0.6, 0.6]
 },
}
Plotly.newPlot("draw",data,layout,{
     editable: true,
    scrollZoom: true,
    showLink: false,
    displaylogo: false,
    modeBarButtonsToRemove: ['sendDataToCloud']
})
```
# Threeで3D描画
THREE.ParametricGeometryがちょうどいいです。これは2つの変数u,vをパラメータにして面を描いてくれる関数です。ジューコフスキー翼は翼型を描くのにuを割り当てて、高さ方向の変化にvを割り当てると、高さ方向に形の異なる3Dの翼を描くことができます。

![Imgur](https://i.imgur.com/LmpAgPr.png)

```javascript
var width = 500;
var height =500;

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45,width/height, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(new THREE.Color("rgb(0,0,0)"));
renderer.setSize(width, height);

var controls =  new THREE.OrbitControls( camera );
var axes = new THREE.AxesHelper(20);
scene.add(axes);

const x0 = -0.05
const y0 = 0.1
const c = 1 

const zukofsky = (x0, y0, c) => {

  const b = c/4 
  const a = Math.sqrt((b-x0)**2+y0**2)
  
  const z = t =>{
    return {
      x: a*Math.cos(t)+x0,
      y: a*Math.sin(t)+y0,
    }
  }
  
  const invZ = t =>{
    const w = (a*Math.cos(t)+x0)**2+(a*Math.sin(t)+y0)**2
    return {
      x: (a*Math.cos(t)+x0)/w, 
      y: -(a*Math.sin(t)+y0)/w, 
    }
  }
  
  const zeta = t => {
    const temp1 = z(t)
    const temp2 = invZ(t)
    const temp3 = {x: 0, y:0}
    temp3.x = temp1.x + b**2*temp2.x
    temp3.y = temp1.y + b**2*temp2.y
    return temp3 
  }
  return zeta
}

const wing1 = zukofsky(x0,y0,c)
const wingGeom1 = (u,v)=>{
  const A = 50
  const temp = wing1(u*2*Math.PI) 
  const x = temp.x*A 
  const y = temp.y*A 
  const z = v*A*2
  return new THREE.Vector3(x,y,z)
}

const createMesh = geometry => {
  const meshMaterial = new THREE.MeshNormalMaterial();
  meshMaterial.side = THREE.DoubleSide;
  const wireFrameMat = new THREE.MeshBasicMaterial();
  wireFrameMat.wireframe = true;
  const plane = THREE.SceneUtils.createMultiMaterialObject(
    geometry, [meshMaterial ,wireFrameMat])
  return plane
} 

const wing = createMesh(new THREE.ParametricGeometry(wingGeom1,50,50,false))
scene.add(wing);

camera.position.x = 100;
camera.position.y = 100;
camera.position.z = 100;


function animate() {
  requestAnimationFrame( animate );
  renderer.render( scene, camera );
  controls.update();
}

document.getElementById("draw")
  .appendChild(renderer.domElement);
  

animate();
```