자석과 나침반을 단순하게 구현한 것.

체크박스에 체크를 하면 자석이 나타난다.

막대자석 모양이 나타나지만 완벽하게 구현되어 있지는 않다..



▽이곳에 플래시가 삽입되어 있습니다.





=====================================================================================






정상파 발생 플래시입니다. 소리를 들어보세요.

(화면에 표시되는 내용은 스피커에 전달될 샘플링 데이터를 나타낸 것으로 정상파와는 맞지 않습니다.)







소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.text.TextField;
import flash.events.MouseEvent;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.text.TextFieldAutoSize;
import flash.media.Sound;
import flash.events.SampleDataEvent;
 
var mySound:Sound = new Sound();
 
var t:Number = 0;
var amplitude:Number = 0.25;
var graph_amplitude:Number = 50/amplitude;
var bmpDat:BitmapData = new BitmapData(400,200,false,0x0);
var bmp:Bitmap = new Bitmap(bmpDat);
bmp.y=50;
addChild(bmp);
 
 
var tfield:TextField = new TextField();
tfield.text = "화면을 누르면 시작.";
tfield.x = 120;
tfield.y = 100;
tfield.autoSize = TextFieldAutoSize.LEFT;
tfield.selectable = false;
var tformat:TextFormat = tfield.getTextFormat();
tformat.color = 0x33cc33;
tformat.align = TextFormatAlign.CENTER;
tfield.setTextFormat(tformat);
addChild(tfield);
stage.addEventListener(MouseEvent.CLICK, mouse_h);
 
 
function sineWaveGenerator(event:SampleDataEvent):void {
    t+=2;
    bmpDat.fillRect(new Rectangle(0,0,400,200),0x0);
    var wave:Number;
    for ( var c:int=0; c<2048; c++ ) {
        wave = getWave(c+event.position,t);
        event.data.writeFloat(wave);
        event.data.writeFloat(wave);
        if(c<800){
            bmpDat.setPixel(c,wave*graph_amplitude+100,0x00ff00);
        }
    }
    bmp.bitmapData = bmpDat;
 
}
 
 
function getWave(p:Number,t:Number):Number
{
    return (Math.sin(0.420*(Number(p+t)/Math.PI/2))+Math.sin(0.420*(Number(p)/Math.PI/2)))*amplitude;
}
 
function mouse_h(evt:MouseEvent):void
{
    mySound.addEventListener(SampleDataEvent.SAMPLE_DATA,sineWaveGenerator);
    mySound.play();
    removeChild(tfield);
}









 1. 플래시


자세한 설명은 아래에 있습니다.







2. 데이터&설명


지구에서 관측되는 화성의 움직임을 플래시로 나타내 본 것입니다.

아래와 같은 조건들을 설정했습니다.


- 공전궤도 모양

원(평면)으로 가정


- 공전궤도 반지름

지구 : 1
화성 : 1.5


-공전속도

지구 : 1.88

화성 : 1


- 궤도경사와 승교점경도

지구 : 7.3˚ 349˚
화성 : 5.7˚ 50˚


- 천구의 중심

태양 (중심을 지구로 잡으면 투영면이 움직여서 알아보기가 불편하고,

태양으로 잡아도 화성의 역행 움직임이 나타나는 모양을 설명하기에는

큰 차이가 없기 때문에 편의상 태양을 기준으로 함.) 


- 관찰자의 고도

황도를 기준으로 pi/13 라디안



지구와 화성의 공전궤도면이 일치하지 않기 때문에

화성이 충 부근에서 역행을 할 때 α모양이나 s모양이 나타나게 됩니다.


예전에 만들었던 것(http://www.tibyte.kr/126)은 두 행성의 공전궤도를 평면상에 둬서 

이런 현상을 확인할 수 없었는데 이번에 입체로 구현해보았습니다.



3. 코드 구현


(1)

Vector3D객체에 각 천체들의 위치벡터를 저장한 후

눈으로 직접 보기 위해 Sprite객체를 움직일 때는 아래와 같은 코드를 사용함.


earth.x = earthPoint.x + sunPoint.x;

earth.y = Math.sin(viewAng)*(earthPoint.y)+sunPoint.y +

 Math.cos(viewAng)*(earthPoint.z)+sunPoint.z;


viewAng는 시점의 고도이며, 이 값에 따라 위치벡터의 y,z값이 Sprite의 y값에 적용됩니다.

모니터는 2D니까 3차원 좌표를 2차원 좌표로 변환해야 하기 때문임.



(2)

공전궤도를 기울이는 함수 inclineObt()


function inclineObt(vec3D:Vector3D,xy:Number=0, zx:Number=0):Vector3D

{

var transVec3D:Vector3D = new Vector3D();

var matrix:Matrix = new Matrix(0,0,0,0);

matrix.a = vec3D.x;

matrix.b = vec3D.z;

matrix.rotate(zx);  //

transVec3D.x = matrix.a;

transVec3D.z = matrix.b;

matrix.a = transVec3D.x;

matrix.b = vec3D.y;

matrix.rotate(xy);

transVec3D.x = matrix.a;

transVec3D.y = matrix.b;

transVec3D.w = vec3D.w;

return transVec3D;

}


궤도경사와 승교점고도 수치에 맞게 공전궤도를 기울인다.

Matrix클래스의 rotate메서드는 이차원 회전행렬 

( cos -sin)
( sin  cos) 를 대상 행렬 앞에 곱함.




(3)

천구면에 투영된 화성의 위치를 구하는 함수


function calcProjPoint(vec1:Vector3D, vec2:Vector3D):Vector3D

{

var direcVec3D:Vector3D = vec2.clone();

direcVec3D.decrementBy(vec1);

var a:Number = direcVec3D.x;

var b:Number = direcVec3D.y;

var c:Number = direcVec3D.z;

var d:Number = vec1.x;

var e:Number = vec1.y;

var f:Number = vec1.z;

/* 이차방정식의 근의 공식으로 투영된 외행성의 위치를 구한다*/

var product:Number = calcQuadratic(a*a+b*b+c*c, 2*(a*d+b*e+c*f), d*d+e*e+f*f-sphereRad*sphereRad);

direcVec3D.scaleBy(product);

return direcVec3D.add(vec1);


}


천구면은 편의상 중심점을 태양의 중심으로 맞춤.

sphereRad 는 천구의 반지름값이므로 투영된 화성의 상은 태양으로부터 항상 sphereRad위치에 있게 됨.

천구면에 투영된 화성의 위치벡터는 (지구의위치벡터 + p*지구에서화성을바라보는벡터) 이므로 p값을 먼저 구해야 함.


즉, 지구벡터+p*(화성-지구벡터)의 거리는 sphereRad와 같으므로

거리 = 거리 방정식을 세워보면 위 코드와 같은 방법으로 p(product)값을 구할 수 있다. (calcQuadratic은 근의 공식으로 이차방정식의 (큰)해를 구하는 함수) 



(4) 

3D천구 뼈대를 그리는 부분


var polygons:Vector.<Vector.<Vector3D>> = new Vector.<Vector.<Vector3D>>(19);

var model2D:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>(19);

for(var i_lati:int = 0; i_lati<19; i_lati++) {

polygons[i_lati] = new Vector.<Vector3D>(36);

model2D[i_lati] = new Vector.<Point>(36);

for(var j_longi:int = 0; j_longi<36; j_longi++) {

polygons[i_lati][j_longi] = new Vector3D();

model2D[i_lati][j_longi] = new Point();

//초기위치 

polygons[i_lati][j_longi].z = radius*Math.sin(getLatitude(i_lati));

polygons[i_lati][j_longi].x = radius*Math.cos(getLatitude(i_lati))*Math.cos(getLongitude(j_longi));

polygons[i_lati][j_longi].y = radius*Math.cos(getLatitude(i_lati))*Math.sin(getLongitude(j_longi));

//시점에따른 변환

model2D[i_lati][j_longi].x = polygons[i_lati][j_longi].x + central.x;

model2D[i_lati][j_longi].y = Math.sin(viewAng)*(polygons[i_lati][j_longi].y)+central.y +

Math.cos(viewAng)*(polygons[i_lati][j_longi].z)+central.z;

}

}

function getLatitude(index:int):Number{return (index*10-90)/180*Math.PI;}

function getLongitude(index:int):Number{return (index*10)/180*Math.PI;} 



Vector에  Vector3D객체와 Point객체를를 2차원으로 할당하고

Vector3D에는 위도를 10도단위로 한층씩 훑어가면서 경선을 이루게 될 36개의 점의 xyz 3차원 좌표를 저장.

Point에는 2차원인 모니터에 표시하기 위해 위에서 구한 xyz좌표를 xy좌표로 변환 .








2007년에 만들었던 플래시인데 큰 오류가 있어서 약간 수정했습니다.

빨간원 : 태양
파란원 : 지구
초록원 : 화성
하얀원&빨간선 : 천구면에 투영된 화성의 겉보기 경로


천구의 천정(태양계의 위쪽)에서 바라본 시점이라서
아래 플래시에서는 역행할 때  경로가 겹쳐지게 되지만

지구와 화성의 공전궤도면이 일치하지 않기 때문에
실제 지구에서 볼 때는 S자 모양이나 α자 모양이 나타납니다.
나중에 한번 3D로도 만들어 봐야겠네요..

12.12.6 수정
3D로 만든 주소입니다.
http://tibyte.kr/141




===============================================================================================



 





사각형 파동의 푸리에 합성입니다.

화면을 클릭해서 켜고 끌 수 있습니다

아래의 막대로 조화모드의 수를 조절할 수 있습니다.



+ Recent posts