如何在HTML5中计算太阳到地球的行星轨道的光学轴线

huangapple go评论68阅读模式
英文:

How to calculate an optical axis line for planetary orbits around the sun to earth in HTML5

问题

我正在从地球的角度创建一个内部太阳系模型,以用于制作占星术的出生图参考。我能够绘制地球-太阳轴和地球-月球轴的光学轴线,但我对剩余的内部行星的三角法一无所知。

以下是一个工作示例。
https://codepen.io/pjdroopypants/pen/wvEKeOm

window.onload = function(){

	var canvas = document.getElementById("canvas"),
	ctx = canvas.getContext("2d"),
	cw = canvas.width,
	ch = canvas.height,
	time = 1;

function circle(radius,color,x,y){
	ctx.beginPath();
	ctx.fillStyle = color;
	ctx.arc(x,y,radius,0,2*Math.PI,true);
	ctx.fill();
	ctx.closePath();
}


function line(color,ax,ay,bx,by){

	ctx.beginPath();
	ctx.moveTo(ax*2,ay);
	ctx.lineTo(bx+0.5,by+0.5);
	ctx.strokeStyle = color;
	ctx.stroke();
	ctx.closePath();

}

var sunDegree = Math.floor(Math.random() * 359) + 1; // 临时的,将使用来自实时行星数据的函数
var merDegree = Math.floor(Math.random() * 359) + 1; // 临时的,将使用来自实时行星数据的函数 
var venDegree = Math.floor(Math.random() * 359) + 1; // 临时的,将使用来自实时行星数据的函数 
var marDegree = Math.floor(Math.random() * 359) + 1; // 临时的,将使用来自实时行星数据的函数 
var mooDegree = Math.floor(Math.random() * 359) + 1; // 临时的,将使用来自实时行星数据的函数 
var interval = 570.0930061551268;

function animate(){

	ctx.save();
	ctx.clearRect(0, 0, 1100, 1100);
	ctx.translate(cw/2,ch/2);

	//地球 
	ctx.rotate(-(time / interval)+ Math.PI);
	circle(15,"blue",0,0);
	ctx.translate(480,0);
	line("blue",-240,0,0,0);
	ctx.translate(-480,0);
	ctx.rotate((time / interval)+ Math.PI);

		//月球
		var moontime = (time / (interval / 13.36996336996337)+mooDegree);
		ctx.rotate(-moontime);
		ctx.translate(23,0);
		circle(3,"black",0,0);
		ctx.translate(457,0);
		line("#6a6a6a",-230,0,0,0);
		ctx.translate(-480,0);
		ctx.rotate(moontime);

	//太阳
	var suntime = time / interval;
	ctx.rotate(-suntime);
	ctx.translate(120,0);
	circle(15,"yellow",0,0);
	ctx.translate(360,0);
	line("yellow",-182,0,0,0);
	ctx translate(-360,0);
	ctx.rotate(suntime);

	//水星
	var mertime = (time / (interval / 4.150568181818182))+merDegree;
	ctx.rotate(-(time / (interval / 4.150568181818182))+merDegree-suntime);
	ctx.translate(40,0);
	circle(15,"#898989",0,0);

	ctx.translate(-40,0);
	ctx.rotate((time / (interval / 4.150568181818182))+merDegree+suntime);

	//金星
	ctx.rotate(-(time / (interval / 1.625500667556742))+venDegree-suntime);
	ctx.translate(80,0);
	circle(15,"#b9955b",0,0);
	ctx.translate(-80,0);
	ctx.rotate((time / (interval / 1.625500667556742))+venDegree);

	//火星
	ctx.rotate(-(time / (interval / 0.5316593886462882))+marDegree);
	ctx.translate(160,0);
	circle(15,"#9f5e13",0,0);
	ctx.translate(-160,0);
	ctx.rotate((time / (interval / 0.5316593886462882))+marDegree);

	ctx.restore();
	time++;
	window.requestAnimationFrame(animate);

}

	window.requestAnimationFrame(animate);

}

我尝试在每次动画迭代中反向旋转,通过减去太阳的旋转角度,但这只会使轴线水平,而不会回到中心。

英文:

I am creating an inner solar sytem model from the percpective of Earth for creating astology birthcharts references. I am able to draw an optical axis line for the Earth - Sun axis, and the Earth - Moon axis but I can not for the life of me figure the trigonometry for the remaining inner planets.
Here is a working pen.
https://codepen.io/pjdroopypants/pen/wvEKeOm

window.onload = function(){
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
cw = canvas.width,
ch = canvas.height,
time = 1;
function circle(radius,color,x,y){
ctx.beginPath();
ctx.fillStyle = color;
ctx.arc(x,y,radius,0,2*Math.PI,true);
ctx.fill();
ctx.closePath();
}
function line(color,ax,ay,bx,by){
ctx.beginPath();
ctx.moveTo(ax*2,ay);
ctx.lineTo(bx+0.5,by+0.5);
ctx.strokeStyle = color;
ctx.stroke();
ctx.closePath();
}
var sunDegree = Math.floor(Math.random() * 359) + 1; //temporary, will use function from live planetary data
var merDegree = Math.floor(Math.random() * 359) + 1; //temporary, will use function from live planetary data 
var venDegree = Math.floor(Math.random() * 359) + 1; //temporary, will use function from live planetary data 
var marDegree = Math.floor(Math.random() * 359) + 1; //temporary, will use function from live planetary data 
var mooDegree = Math.floor(Math.random() * 359) + 1; //temporary, will use function from live planetary data 
var interval = 570.0930061551268;
function animate(){
ctx.save();
ctx.clearRect(0, 0, 1100, 1100);
ctx.translate(cw/2,ch/2);
//Earth 
ctx.rotate(-(time / interval)+ Math.PI);
circle(15,"blue",0,0);
ctx.translate(480,0);
line("blue",-240,0,0,0);
ctx.translate(-480,0);
ctx.rotate((time / interval)+ Math.PI);
//Moon
var moontime = (time / (interval / 13.36996336996337)+mooDegree);
ctx.rotate(-moontime);
ctx.translate(23,0);
circle(3,"black",0,0);
ctx.translate(457,0);
line("#6a6a6a",-230,0,0,0);
ctx.translate(-480,0);
ctx.rotate(moontime);
//Sun
var suntime = time / interval;
ctx.rotate(-suntime);
ctx.translate(120,0);
circle(15,"yellow",0,0);
ctx.translate(360,0);
line("yellow",-182,0,0,0);
ctx.translate(-360,0);
ctx.rotate(suntime);
//Mercury
var mertime = (time / (interval / 4.150568181818182))+merDegree;
ctx.rotate(-(time / (interval / 4.150568181818182))+merDegree-suntime);
ctx.translate(40,0);
circle(15,"#898989",0,0);
ctx.translate(-40,0);
ctx.rotate((time / (interval / 4.150568181818182))+merDegree+suntime);
//Venus
ctx.rotate(-(time / (interval / 1.625500667556742))+venDegree-suntime);
ctx.translate(80,0);
circle(15,"#b9955b",0,0);
ctx.translate(-80,0);
ctx.rotate((time / (interval / 1.625500667556742))+venDegree);
//Mars
ctx.rotate(-(time / (interval / 0.5316593886462882))+marDegree);
ctx.translate(160,0);
circle(15,"#9f5e13",0,0);
ctx.translate(-160,0);
ctx.rotate((time / (interval / 0.5316593886462882))+marDegree);
ctx.restore();
time++;
window.requestAnimationFrame(animate);
}
window.requestAnimationFrame(animate);
}

I attempted to reverse rotate each animation iteration by subtracting the suns rotating angle but that just makes the axis line horizontal and not back to center.

答案1

得分: 0

## 使用对象封装

你的代码很混乱

你需要封装各个部分以便可以单独处理它们

下面的示例使用工厂模式定义了行星以创建行星对象

每个行星都有轨道角度速率和与其轨道的距离例如水星金星地球火星都绕太阳运动月球绕地球运动

行星按照轨道顺序创建也就是说在创建行星之前不能创建其轨道上的行星

在每一帧动画中每个行星的位置都相对于其轨道上的行星按照创建顺序计算

在渲染行星之前我们想要将视图居中在所选行星上在本例中为地球)。居中的行星位置用于创建一个全局矩阵将所有行星移动到正确的位置

然后在绘制每个行星时将全局矩阵与行星的矩阵相乘 `ctx.setTransform(...globalMat); ctx.transform(this.cos, this.sin, -this.sin, this.cos, this.x, this.y);` 并绘制结果

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

    requestAnimationFrame(mainLoop);
    const ctx = canvas.getContext("2d");
    const TAU = Math.PI * 2;
    const centerOnPlanetName = "Earth";  // 要居中视图的行星名称
    const globalMatrix = [1,0,0,1,0,0];  // 保存行星位置以跟踪
    const solSystem = {};                // 按名称保存行星
    const planets = [];                  // 按创建顺序保存行星
    const planetCommon = {               // 行星的通用属性
         x: 0, y: 0, cos: 1, sin: 0,
         update(time) {
             this.ang = this.startAng + this.orbitalSpeed * time;
             this.cos = Math.cos(this.ang);
             this.sin = Math.sin(this.ang);
             if (this.orbits) {          // 检查是否绕着某物体运动
                 this.x = this.orbits.x + this.cos * this.dist;
                 this.y = this.orbits.y + this.sin * this.dist;
             } 
         },
         draw(ctx, globalMat) {
             ctx.setTransform(...globalMat);
             ctx.transform(this.cos, this.sin, -this.sin, this.cos, this.x, this.y);
             ctx.fillStyle = this.color;
             ctx.beginPath();
             ctx.arc(0, 0, this.radius, 0, TAU);
             ctx.fill();
             if (this.dirTo !== undefined) {
                 ctx.beginPath();
                 const ax = Math.cos(this.dirTo);
                 const ay = Math.sin(this.dirTo);
                 ctx.lineTo(ax * this.radius * 1.5, ay * this.radius * 1.5);
                 ctx.lineTo(ax * this.distTo, ay * this.distTo);
                 ctx.stroke();         
             }
         },
         directionTo(planet) {
             if (planet !== this) {
                  this.dirTo = Math.atan2(planet.y - this.y, planet.x - this.x) - this.ang;
                  this.distTo = Math.hypot(planet.y - this.y, planet.x - this.x);
             } else {
                  this.dirTo = undefined;
             }
         }
    };
    const planet = (name, orbitsName, dist, orbitalSpeed, startAng, radius, color) => {
        planets.push(solSystem[name] = {
            orbits: solSystem[orbitsName], // 设置新行星绕着的行星
            dist,                          // 离轨道物体的距离
            orbitalSpeed,                  // 每个时间单位的弧度
            startAng,                      // 弧度中的起始角度
            radius,
            color,
            ...planetCommon,
         });
    };
    planet("Sun", undefined,     0, 0.8, - Math.PI, 20, "yellow");
    planet("Mercury", "Sun",    45,   2,         0,  6, "#888");
    planet("Venus",   "Sun",    70, 1.2,         0, 15, "#CC8");
    planet("Earth",   "Sun",   120, 0.8,         0, 16, "#39B");
    planet("Mars",    "Sun",   175, 0.4,         0, 10, "#B43");
    planet("Moon",    "Earth",  30,   5,         0,  3, "#444");

    function centerOn(cx, cy, planet) {
        globalMatrix[4] = cx - planet.x;
        globalMatrix[5] = cy - planet.y;
    }

    function mainLoop(time) {
        time /= 1000;
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        planets.forEach(planet => planet.update(time));
        planets.forEach(planet => planet.directionTo(solSystem[centerOnPlanetName]));
        centerOn(ctx.canvas.width * 0.5, ctx.canvas.height * 0.5, solSystem[centerOnPlanetName]);
        planets.forEach(planet => planet.draw(ctx, globalMatrix));
        requestAnimationFrame(mainLoop);
    }

<!-- language: lang-css -->

    canvas {
     border: 1px solid black;
    }

<!-- language: lang-html -->

    <canvas id="canvas" width="600" height="600"></canvas>

&lt;!-- end snippet --&gt;
英文:

Encapsulate using objects

Your code is a mess

You need to encapsulate the various parts so you can work with them individually.

The example below defines planets using a factory pattern to create planets as objects.

Each planet gets orbital ang, rate, and distance from the planet they orbit. Eg Mercury, Venus, Earth, Mars all orbit the Sun, and the Moon orbits the Earth.

Planets are created in orbital order. IE can not create planet before you create the planet it orbits.

On each animation frame each planet's position is calculated relative to the planet it orbits in the same order as they were created.

Before rendering the planet we want to center the view on a selected planet (in this case the Earth). The centered planets position is used to create a global matrix that will move all planets to the correct position.

Then when drawing each planet we multiply the global matrix by the planet's matrix ctx.setTransform(...globalMat); ctx.transform(this.cos, this.sin, -this.sin, this.cos, this.x, this.y); and draw the result

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

requestAnimationFrame(mainLoop);
const ctx = canvas.getContext(&quot;2d&quot;);
const TAU = Math.PI * 2;
const centerOnPlanetName = &quot;Earth&quot;;  // Planet name to center view on
const globalMatrix = [1,0,0,1,0,0];  // holds position of planet to track
const solSystem = {};                // holds planets by name
const planets = [];                  // holds planets in order of created
const planetCommon = {               // common properties of planets
x: 0, y: 0, cos: 1, sin: 0,
update(time) {
this.ang = this.startAng + this.orbitalSpeed * time;
this.cos = Math.cos(this.ang);
this.sin = Math.sin(this.ang);
if (this.orbits) {          // Check if orbiting something
this.x = this.orbits.x + this.cos * this.dist;
this.y = this.orbits.y + this.sin * this.dist;
} 
},
draw(ctx, globalMat) {
ctx.setTransform(...globalMat);
ctx.transform(this.cos, this.sin, -this.sin, this.cos, this.x, this.y);
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(0, 0, this.radius, 0, TAU);
ctx.fill();
if (this.dirTo !== undefined) {
ctx.beginPath();
const ax = Math.cos(this.dirTo);
const ay = Math.sin(this.dirTo);
ctx.lineTo(ax * this.radius * 1.5, ay * this.radius * 1.5);
ctx.lineTo(ax * this.distTo, ay * this.distTo);
ctx.stroke();         
}
},
directionTo(planet) {
if (planet !== this) {
this.dirTo = Math.atan2(planet.y - this.y, planet.x - this.x) - this.ang;
this.distTo = Math.hypot(planet.y - this.y, planet.x - this.x);
} else {
this.dirTo = undefined;
}
}
};
const planet = (name, orbitsName, dist, orbitalSpeed, startAng, radius, color) =&gt; {
planets.push(solSystem[name] = {
orbits: solSystem[orbitsName], // Set planet new planet orbits
dist,                          // dist from orbiting body
orbitalSpeed,                  // in radians per time unit
startAng,                      // starting angle in radians
radius,
color,
...planetCommon,
});
};
planet(&quot;Sun&quot;, undefined,     0, 0.8, - Math.PI, 20, &quot;yellow&quot;);
planet(&quot;Mercury&quot;, &quot;Sun&quot;,    45,   2,         0,  6, &quot;#888&quot;);
planet(&quot;Venus&quot;,   &quot;Sun&quot;,    70, 1.2,         0, 15, &quot;#CC8&quot;);
planet(&quot;Earth&quot;,   &quot;Sun&quot;,   120, 0.8,         0, 16, &quot;#39B&quot;);
planet(&quot;Mars&quot;,    &quot;Sun&quot;,   175, 0.4,         0, 10, &quot;#B43&quot;);
planet(&quot;Moon&quot;,    &quot;Earth&quot;,  30,   5,         0,  3, &quot;#444&quot;);
function centerOn(cx, cy, planet) {
globalMatrix[4] = cx - planet.x;
globalMatrix[5] = cy - planet.y;
}
function mainLoop(time) {
time /= 1000;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
planets.forEach(planet =&gt; planet.update(time));
planets.forEach(planet =&gt; planet.directionTo(solSystem[centerOnPlanetName]));
centerOn(ctx.canvas.width * 0.5, ctx.canvas.height * 0.5, solSystem[centerOnPlanetName]);
planets.forEach(planet =&gt; planet.draw(ctx, globalMatrix));
requestAnimationFrame(mainLoop);
}

<!-- language: lang-css -->

canvas {
border: 1px solid black;
}

<!-- language: lang-html -->

&lt;canvas id=&quot;canvas&quot; width=&quot;600&quot; height=&quot;600&quot;&gt;&lt;/canvas&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年2月19日 07:54:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/75497153.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定