Entry tags:
Сэндбокс звездных систем
Наткнулся на флешевый сэндбокс - симуляцию звездных систем.
К сожалению, там только один сценарий - образование планетной системы из облака пыли(обычно получается центральная "звезда" с 1-2 крупными планетами). Можно составлять свои системы ручками, но это дико неудобно. Порывшись, нашел исходники.И завертелось...
На выходе - МОЯ ВЕРСИЯ, флеш сразу открывается в браузере.
Симуляция спиральных рукавов галактик

Симуляция точек Лагранжа

А также симуляция сферы Хилла, розетты Кемплера(которую кукольники Нивена использовали для своих планет), подковообразные орбиты и маленькую Солнечную систему в масштабе(внутренние планеты, Юпитер и схематически изображенный пояс астероидов).
Сделал симуляцию кольца частиц вокруг планеты и пытался получить на ней резонансные кольца, но не получалось. Судя по этой статье, на образование колец нужны десятки миллионов лет(~миллионы оборотов), а это уже выходит за рамки простенькой модели.
Update. Что пишет по этому вопросу don_beaver(Горькавый):
Щели в кольцах - вроде Кассини от резонанса от Мимаса - действительно медленно образуются и там механика очень непростая - нужно учитывать и вязкость, и самогравитацию. В моей с Фридманом книжке есть приложение на эту тему, написанное с Хоружим.
Резонансные кольца типа Урана возникают по другому - там нужно иметь спутник с внешними резонансами и тормозящий эффект на частицах, который ползут к планете и застревают в резонансах на какое-то время. Или наоборот (как возле Урана) - внутренние резонансы и ползущие наружу частицы. Это я считал в английском варианте книжки.
Если хочется 3Д, нормального интерфейса и прочего - лучше сразу качать Universe Sandbox Мне лично реализация на флеше понравилась отсутствием необходимости установки.
1. Обычно первым делом пилят Эйлера, иногда даже изобретают его самостоятельно. Интегрирование Верле не сложнее, но точнее.
2. Сложность обычного алгоритма - n^2. Есть алгоритмы с меньшей сложностью, например Barnes–Hut.
https://en.wikipedia.org/wiki/Leapfrog_integration
http://www.artcompsci.org/vol_1/v1_web/node34.html
public static function planet(center:Particle, Rperigee:Number, Rapogee:Number, particle_mass:Number):void
{
var alpha:Number = Math.PI*2*Math.random();
var center_x:Number = center.pos_x;
var center_y:Number = center.pos_y;
var center_mass:Number = center.mass;
if(Rapogee<Rperigee) {
var swap:Number = Rapogee;
Rapogee = Rperigee;
Rperigee = swap;
}
var va:Number = Math.sqrt(2*center_mass*Rperigee/(Rapogee*(Rapogee+Rperigee)));
var e:Number = (Rapogee - Rperigee) / (Rapogee + Rperigee);
var p:Number = Rapogee*(1-e);
var theta:Number = 0;
//theta = Math.PI*i;
var pi:Number = p/(1-e*Math.cos(theta));
var x:Number = pi*Math.cos(theta);
var y:Number = pi*Math.sin(theta);
var theta1:Number = theta + 0.0001;
var pi1:Number = p/(1-e*Math.cos(theta1));
var x1:Number = pi1*Math.cos(theta1);
var y1:Number = pi1*Math.sin(theta1);
x1 = x1 - x;
y1 = y1 - y;
var length:Number = Math.sqrt(x1*x1 + y1*y1);
x1 = x1/length;
y1 = y1/length;
var length2:Number = Math.sqrt(x*x + y*y);
var x2:Number = y/length2;
var y2:Number = -x/length2;
var factor:Number = Rapogee/pi/(x1*x2+y1*y2);
var xv:Number = va*factor*x1;
var yv:Number = va*factor*y1;
var cosa:Number = Math.cos(alpha);
var sina:Number = Math.sin(alpha);
var vxa:Number = (xv*cosa) - (yv*sina);
var vya:Number = (xv*sina) + (yv*cosa);
var xa:Number = (x*cosa) - (y*sina);
var ya:Number = (x*sina) + (y*cosa);
var ring_particle:Particle = new Particle(particle_mass, vxa, vya, center_x+xa, center_y+ya);
Gravity.view.addChild(ring_particle);
Gravity.particles.push(ring_particle);
center.vel_x = center.vel_x - vxa*(particle_mass/center.mass)
center.vel_y = center.vel_y - vya*(particle_mass/center.mass)
}
public static function generate_galaxy():void
{
autoclear();
var randomN:Number = Gravity.app.random_count.text; // 100
var curvatureN:Number = Gravity.app.curvature_count.text; // 100
var spiralN:Number = Gravity.app.spiral_count.text; // 2
var center_x:Number = Gravity.app.parent.parent.stageWidth/2;
var center_y:Number = Gravity.app.parent.parent.stageHeight/2;
var saturn:Particle = new Particle(saturn_m, 0, 0, center_x, center_y);
Gravity.view.addChild(saturn);
Gravity.particles.push(saturn);
//generate_moon(210, saturn_m, 0.00001, 1);
//generate_moon(90, saturn_m, 0.00001, 1);
var Rrange:Number = 270;
var Rmin:Number = 80;
for (var i9:Number = Rmin+Rrange; i9 > Rmin ; i9-=1 ){
var Rratio:Number = (i9-Rmin) / Rrange * 2 * curvatureN / 100;
for (var i8:Number = 0; i8 < 15 ; i8++){
var e:Number = 2;
var Erandom:Number = (Math.random()-0.5)/500*randomN;
var Arandom:Number = (Math.random()-0.5)*Math.PI/1000*randomN;
for (var i10:Number = 0; i10 < spiralN ; i10+=1 )
generate_galaxy_particle(saturn_m, 1, i9, i9/(e+Erandom), Math.PI/2*Rratio+Arandom + Math.PI*2/spiralN*i10);
//generate_galaxy_particle(saturn_m, 1, i9, i9/(e+Erandom), Math.PI+Math.PI/2*Rratio+Arandom);
//generate_galaxy_particle(saturn_m, 1, i9, i9/2, Math.PI/2+Math.PI/2*Rratio);
//generate_galaxy_particle(saturn_m, 1, i9, i9/2, Math.PI/2+Math.PI+Math.PI/2*Rratio);
}
}
for (var i8:Number = 0; i8 < 3000 ; i8++){
generate_galaxy_particle(saturn_m, 1, (Rmin-20)*Math.random()+25, (Rmin-20)*Math.random()+25, Math.PI*2*Math.random());
}
for (var i8:Number = 0; i8 < 1000 ; i8++){
generate_galaxy_particle(saturn_m, 1, (Rrange)*Math.random()+Rmin, (Rrange)*Math.random()+Rmin, Math.PI*2*Math.random());
}
}
public static function generate_galaxy_particle(center_mass:Number, particle_mass:Number,
Rapogee:Number, Rperigee:Number, alpha:Number):void
{
var center_x:Number = Gravity.app.parent.parent.stageWidth/2;
var center_y:Number = Gravity.app.parent.parent.stageHeight/2;
if(Rapogee<Rperigee) {
var swap:Number = Rapogee;
Rapogee = Rperigee;
Rperigee = swap;
}
//var v:Number = Math.sqrt(planet_weight/r);
var va:Number = Math.sqrt(2*center_mass*Rperigee/(Rapogee*(Rapogee+Rperigee)));
//var vp:Number = Math.sqrt(2*center_mass*Rapogee/(Rperigee*(Rapogee+Rperigee)));
var e:Number = (Rapogee - Rperigee) / (Rapogee + Rperigee);
var p:Number = Rapogee*(1-e);
for (var i:Number = 0; i < 100 ; i++) {
var theta:Number = Math.random()*Math.PI*2;
//theta = Math.PI*i;
var pi:Number = p/(1-e*Math.cos(theta));
var x:Number = pi*Math.cos(theta);
var y:Number = pi*Math.sin(theta);
var theta1:Number = theta + 0.0001;
var pi1:Number = p/(1-e*Math.cos(theta1));
var x1:Number = pi1*Math.cos(theta1);
var y1:Number = pi1*Math.sin(theta1);
x1 = x1 - x;
y1 = y1 - y;
var length:Number = Math.sqrt(x1*x1 + y1*y1);
x1 = x1/length;
y1 = y1/length;
var length2:Number = Math.sqrt(x*x + y*y);
var x2:Number = y/length2;
var y2:Number = -x/length2;
var factor:Number = Rapogee/pi/(x1*x2+y1*y2);
var xv:Number = va*factor*x1;
var yv:Number = va*factor*y1;
var factorRandom:Number = Math.random()*factor;
if(factorRandom<0)
factorRandom *= -1;
if((factorRandom)<0.01){
var cosa:Number = Math.cos(alpha);
var sina:Number = Math.sin(alpha);
var vxa:Number = (xv*cosa) - (yv*sina);
var vya:Number = (xv*sina) + (yv*cosa);
var xa:Number = (x*cosa) - (y*sina);
var ya:Number = (x*sina) + (y*cosa);
var ring_particle:Particle = new Particle(particle_mass, vxa, vya, center_x+xa, center_y+ya);
Gravity.view.addChild(ring_particle);
Gravity.particles.push(ring_particle);
}
}
}
К сожалению, там только один сценарий - образование планетной системы из облака пыли(обычно получается центральная "звезда" с 1-2 крупными планетами). Можно составлять свои системы ручками, но это дико неудобно. Порывшись, нашел исходники.И завертелось...
На выходе - МОЯ ВЕРСИЯ, флеш сразу открывается в браузере.
Симуляция спиральных рукавов галактик

Симуляция точек Лагранжа

А также симуляция сферы Хилла, розетты Кемплера(которую кукольники Нивена использовали для своих планет), подковообразные орбиты и маленькую Солнечную систему в масштабе(внутренние планеты, Юпитер и схематически изображенный пояс астероидов).
Сделал симуляцию кольца частиц вокруг планеты и пытался получить на ней резонансные кольца, но не получалось. Судя по этой статье, на образование колец нужны десятки миллионов лет(~миллионы оборотов), а это уже выходит за рамки простенькой модели.
Update. Что пишет по этому вопросу don_beaver(Горькавый):
Щели в кольцах - вроде Кассини от резонанса от Мимаса - действительно медленно образуются и там механика очень непростая - нужно учитывать и вязкость, и самогравитацию. В моей с Фридманом книжке есть приложение на эту тему, написанное с Хоружим.
Резонансные кольца типа Урана возникают по другому - там нужно иметь спутник с внешними резонансами и тормозящий эффект на частицах, который ползут к планете и застревают в резонансах на какое-то время. Или наоборот (как возле Урана) - внутренние резонансы и ползущие наружу частицы. Это я считал в английском варианте книжки.
Если хочется 3Д, нормального интерфейса и прочего - лучше сразу качать Universe Sandbox Мне лично реализация на флеше понравилась отсутствием необходимости установки.
1. Обычно первым делом пилят Эйлера, иногда даже изобретают его самостоятельно. Интегрирование Верле не сложнее, но точнее.
2. Сложность обычного алгоритма - n^2. Есть алгоритмы с меньшей сложностью, например Barnes–Hut.
https://en.wikipedia.org/wiki/Leapfrog_integration
http://www.artcompsci.org/vol_1/v1_web/node34.html
public static function planet(center:Particle, Rperigee:Number, Rapogee:Number, particle_mass:Number):void
{
var alpha:Number = Math.PI*2*Math.random();
var center_x:Number = center.pos_x;
var center_y:Number = center.pos_y;
var center_mass:Number = center.mass;
if(Rapogee<Rperigee) {
var swap:Number = Rapogee;
Rapogee = Rperigee;
Rperigee = swap;
}
var va:Number = Math.sqrt(2*center_mass*Rperigee/(Rapogee*(Rapogee+Rperigee)));
var e:Number = (Rapogee - Rperigee) / (Rapogee + Rperigee);
var p:Number = Rapogee*(1-e);
var theta:Number = 0;
//theta = Math.PI*i;
var pi:Number = p/(1-e*Math.cos(theta));
var x:Number = pi*Math.cos(theta);
var y:Number = pi*Math.sin(theta);
var theta1:Number = theta + 0.0001;
var pi1:Number = p/(1-e*Math.cos(theta1));
var x1:Number = pi1*Math.cos(theta1);
var y1:Number = pi1*Math.sin(theta1);
x1 = x1 - x;
y1 = y1 - y;
var length:Number = Math.sqrt(x1*x1 + y1*y1);
x1 = x1/length;
y1 = y1/length;
var length2:Number = Math.sqrt(x*x + y*y);
var x2:Number = y/length2;
var y2:Number = -x/length2;
var factor:Number = Rapogee/pi/(x1*x2+y1*y2);
var xv:Number = va*factor*x1;
var yv:Number = va*factor*y1;
var cosa:Number = Math.cos(alpha);
var sina:Number = Math.sin(alpha);
var vxa:Number = (xv*cosa) - (yv*sina);
var vya:Number = (xv*sina) + (yv*cosa);
var xa:Number = (x*cosa) - (y*sina);
var ya:Number = (x*sina) + (y*cosa);
var ring_particle:Particle = new Particle(particle_mass, vxa, vya, center_x+xa, center_y+ya);
Gravity.view.addChild(ring_particle);
Gravity.particles.push(ring_particle);
center.vel_x = center.vel_x - vxa*(particle_mass/center.mass)
center.vel_y = center.vel_y - vya*(particle_mass/center.mass)
}
public static function generate_galaxy():void
{
autoclear();
var randomN:Number = Gravity.app.random_count.text; // 100
var curvatureN:Number = Gravity.app.curvature_count.text; // 100
var spiralN:Number = Gravity.app.spiral_count.text; // 2
var center_x:Number = Gravity.app.parent.parent.stageWidth/2;
var center_y:Number = Gravity.app.parent.parent.stageHeight/2;
var saturn:Particle = new Particle(saturn_m, 0, 0, center_x, center_y);
Gravity.view.addChild(saturn);
Gravity.particles.push(saturn);
//generate_moon(210, saturn_m, 0.00001, 1);
//generate_moon(90, saturn_m, 0.00001, 1);
var Rrange:Number = 270;
var Rmin:Number = 80;
for (var i9:Number = Rmin+Rrange; i9 > Rmin ; i9-=1 ){
var Rratio:Number = (i9-Rmin) / Rrange * 2 * curvatureN / 100;
for (var i8:Number = 0; i8 < 15 ; i8++){
var e:Number = 2;
var Erandom:Number = (Math.random()-0.5)/500*randomN;
var Arandom:Number = (Math.random()-0.5)*Math.PI/1000*randomN;
for (var i10:Number = 0; i10 < spiralN ; i10+=1 )
generate_galaxy_particle(saturn_m, 1, i9, i9/(e+Erandom), Math.PI/2*Rratio+Arandom + Math.PI*2/spiralN*i10);
//generate_galaxy_particle(saturn_m, 1, i9, i9/(e+Erandom), Math.PI+Math.PI/2*Rratio+Arandom);
//generate_galaxy_particle(saturn_m, 1, i9, i9/2, Math.PI/2+Math.PI/2*Rratio);
//generate_galaxy_particle(saturn_m, 1, i9, i9/2, Math.PI/2+Math.PI+Math.PI/2*Rratio);
}
}
for (var i8:Number = 0; i8 < 3000 ; i8++){
generate_galaxy_particle(saturn_m, 1, (Rmin-20)*Math.random()+25, (Rmin-20)*Math.random()+25, Math.PI*2*Math.random());
}
for (var i8:Number = 0; i8 < 1000 ; i8++){
generate_galaxy_particle(saturn_m, 1, (Rrange)*Math.random()+Rmin, (Rrange)*Math.random()+Rmin, Math.PI*2*Math.random());
}
}
public static function generate_galaxy_particle(center_mass:Number, particle_mass:Number,
Rapogee:Number, Rperigee:Number, alpha:Number):void
{
var center_x:Number = Gravity.app.parent.parent.stageWidth/2;
var center_y:Number = Gravity.app.parent.parent.stageHeight/2;
if(Rapogee<Rperigee) {
var swap:Number = Rapogee;
Rapogee = Rperigee;
Rperigee = swap;
}
//var v:Number = Math.sqrt(planet_weight/r);
var va:Number = Math.sqrt(2*center_mass*Rperigee/(Rapogee*(Rapogee+Rperigee)));
//var vp:Number = Math.sqrt(2*center_mass*Rapogee/(Rperigee*(Rapogee+Rperigee)));
var e:Number = (Rapogee - Rperigee) / (Rapogee + Rperigee);
var p:Number = Rapogee*(1-e);
for (var i:Number = 0; i < 100 ; i++) {
var theta:Number = Math.random()*Math.PI*2;
//theta = Math.PI*i;
var pi:Number = p/(1-e*Math.cos(theta));
var x:Number = pi*Math.cos(theta);
var y:Number = pi*Math.sin(theta);
var theta1:Number = theta + 0.0001;
var pi1:Number = p/(1-e*Math.cos(theta1));
var x1:Number = pi1*Math.cos(theta1);
var y1:Number = pi1*Math.sin(theta1);
x1 = x1 - x;
y1 = y1 - y;
var length:Number = Math.sqrt(x1*x1 + y1*y1);
x1 = x1/length;
y1 = y1/length;
var length2:Number = Math.sqrt(x*x + y*y);
var x2:Number = y/length2;
var y2:Number = -x/length2;
var factor:Number = Rapogee/pi/(x1*x2+y1*y2);
var xv:Number = va*factor*x1;
var yv:Number = va*factor*y1;
var factorRandom:Number = Math.random()*factor;
if(factorRandom<0)
factorRandom *= -1;
if((factorRandom)<0.01){
var cosa:Number = Math.cos(alpha);
var sina:Number = Math.sin(alpha);
var vxa:Number = (xv*cosa) - (yv*sina);
var vya:Number = (xv*sina) + (yv*cosa);
var xa:Number = (x*cosa) - (y*sina);
var ya:Number = (x*sina) + (y*cosa);
var ring_particle:Particle = new Particle(particle_mass, vxa, vya, center_x+xa, center_y+ya);
Gravity.view.addChild(ring_particle);
Gravity.particles.push(ring_particle);
}
}
}