shmodot/scripts/orbits/Barycenter.cs

144 lines
3.2 KiB
C#

using Godot;
using System;
using System.Collections.Generic;
using Vim.Math3d;
[Tool]
public class Barycenter : Node, IPointMass
{
[Export]
private NodePath[] _pointMassPaths;
private double _semiMajorAxis;
[Export]
private double SemiMajorAxis
{
get => _semiMajorAxis;
set
{
_semiMajorAxis = value;
if (!Engine.EditorHint) return;
InvalidateGeometry();
}
}
private double _eccentricity;
[Export(PropertyHint.Range, "0,1")]
private double Eccentricity
{
get => _eccentricity;
set
{
_eccentricity = value;
if (!Engine.EditorHint) return;
InvalidateGeometry();
}
}
public double Mass
{
get
{
double mass = 0;
foreach (var orbiter in Orbiters)
{
mass += orbiter.PointMass.Mass;
}
return mass;
}
}
public DVector3 Position { get; set; }
private ImmediateGeometry _orbitGeometry = null;
public ImmediateGeometry OrbitGeometry
{
get
{
if (_orbitGeometry == null)
{
_orbitGeometry = new ImmediateGeometry();
var m = new SpatialMaterial();
m.VertexColorUseAsAlbedo = true;
m.FlagsUnshaded = true;
_orbitGeometry.MaterialOverride = m;
AddChild(_orbitGeometry);
}
return _orbitGeometry;
}
}
private struct Orbiter
{
public IPointMass PointMass { get; set; }
public IOrbit Orbit { get; set; }
}
private Orbiter[] _orbiters = null;
private Orbiter[] Orbiters
{
get
{
if (_orbiters == null)
{
var length = _pointMassPaths.Length;
_orbiters = new Orbiter[length];
for (int i = 0; i < length; i++)
{
var pointMass = GetNode<IPointMass>(_pointMassPaths[i]);
var orbit = new Orbit(this, pointMass);
var orbiter = new Orbiter
{
PointMass = pointMass,
Orbit = orbit
};
_orbiters[i] = orbiter;
}
}
return _orbiters;
}
}
private IOrbit[] _orbits;
private IOrbit[] Orbits
{
get
{
if (_orbits == null)
{
}
return _orbits;
}
}
private float _time = 0;
[Export]
private float _speed = 3f;
public override void _Process(float delta)
{
_time += delta * _speed;
InvalidateGeometry();
}
private void InvalidateGeometry()
{
for (int i = 0; i < Orbiters.Length; i++)
{
var orbiter = Orbiters[i];
var orbit = orbiter.Orbit;
orbit.Ellipse = new Ellipse(SemiMajorAxis, Eccentricity);
orbit.Draw(OrbitGeometry);
var t = _time + i * Math.PI;
orbiter.PointMass.Position = orbit.GetPosition(t);
}
}
}