Skip to content

Commit

Permalink
Improved exception reporting.
Browse files Browse the repository at this point in the history
Exception text has been reworded to be more user-centric than
developer-centric, and a wrapper has been added to attach orbital element
names to exceptions thrown by probability distributions.

Closes #28.
  • Loading branch information
Starstrider42 committed Mar 2, 2017
1 parent acf9b36 commit fcccd14
Show file tree
Hide file tree
Showing 16 changed files with 243 additions and 243 deletions.
65 changes: 38 additions & 27 deletions src/AsteroidGroups/Flyby.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,41 +93,41 @@ public Orbit drawOrbit() {

Debug.Log("[CustomAsteroids]: drawing orbit from " + name);

double deltaV = vSoi.draw();
double deltaT = warnTime.draw();
double deltaV = wrappedDraw(vSoi, name, "vSoi");
double deltaT = wrappedDraw(warnTime, name, "warnTime");

if (deltaV <= 0.0) {
throw new InvalidOperationException("[CustomAsteroids]: must have positive SOI entry speed (generated "
+ deltaV + ")");
throw new InvalidOperationException(
$"Asteroids in group '{name}' must have positive SOI entry speed (generated {deltaV})");
}
// Negative deltaT is allowed

double peri;
switch (approach.getParam()) {
case ApproachRange.Type.ImpactParameter:
double b = approach.draw();
case ApproachRange.Type.ImpactParameter:
double b = wrappedDraw(approach, name, "approach");
if (b < 0.0) {
throw new InvalidOperationException("[CustomAsteroids]: cannot have negative impact parameter (generated "
+ b + ")");
throw new InvalidOperationException(
$"Asteroids in group '{name}' cannot have negative impact parameters (generated {b})");
}
double a = -body.gravParameter / (deltaV * deltaV);
double x = b / a;
peri = a * (1.0 - Math.Sqrt(x * x + 1.0));
break;
case ApproachRange.Type.Periapsis:
peri = approach.draw();
case ApproachRange.Type.Periapsis:
peri = wrappedDraw (approach, name, "approach");
if (peri < 0.0) {
throw new InvalidOperationException("[CustomAsteroids]: cannot have negative periapsis (generated "
+ peri + ")");
throw new InvalidOperationException(
$"Asteroids in group '{name}' cannot have negative periapses (generated {peri})");
}
break;
default:
throw new InvalidOperationException("[CustomAsteroids]: cannot describe approach distance using type "
+ approach.getParam());
throw new InvalidOperationException(
$"Asteroids in group '{name}' cannot describe approach distance using type {approach.getParam()}");
}
#if DEBUG
Debug.Log(String.Format("Asteroid will pass {0} m from {1} in {2} Kerbin days. V_infinity = {3} m/s.",
peri, targetBody, deltaT / (6.0 * 3600.0), deltaV));
Debug.Log($"[CustomAsteroids]: Asteroid will pass {peri} m from {targetBody} in {deltaT / (6.0 * 3600.0)} Kerbin days. "
+ $"V_infinity = {deltaV} m/s.");
#endif

Orbit newOrbit = createHyperbolicOrbit(body, peri, deltaV, Planetarium.GetUniversalTime() + deltaT);
Expand All @@ -140,6 +140,16 @@ public Orbit drawOrbit() {
return newOrbit;
}

private double wrappedDraw(ValueRange property, string group, string propertyName)
{
try {
return property.draw ();
} catch (ArgumentException e) {
throw new InvalidOperationException (
$"Could not set orbit property '{propertyName}' for group '{group}'.", e);
}
}

/// <summary>
/// Creates a hyperbolic orbit around the given celestial body.
/// </summary>
Expand All @@ -153,10 +163,10 @@ public Orbit drawOrbit() {
/// of bounds.</exception>
private static Orbit createHyperbolicOrbit(CelestialBody body, double periapsis, double vInf, double utPeri) {
if (vInf <= 0.0) {
throw new ArgumentException("Hyperbolic orbits must have positive excess speed, gave " + vInf, "vInf");
throw new ArgumentException($"Hyperbolic orbits must have positive excess speed, gave {vInf} vInf");
}
if (periapsis < 0.0) {
throw new ArgumentException("Orbits cannot have a negative periapsis, gave " + periapsis, "periapsis");
throw new ArgumentException($"Orbits cannot have a negative periapsis, gave {periapsis} periapsis");
}

double a = -body.gravParameter / (vInf * vInf);
Expand All @@ -167,8 +177,8 @@ private static Orbit createHyperbolicOrbit(CelestialBody body, double periapsis,
double lAn = RandomDist.drawAngle();
double aPe = RandomDist.drawAngle();

Debug.Log("[CustomAsteroids]: new hyperbolic orbit around " + body.bodyName + " at " + a + " m, e = " + e
+ ", i = " + i + ", aPe = " + aPe + ", lAn = " + lAn);
Debug.Log($"[CustomAsteroids]: new hyperbolic orbit around {body.bodyName} at {a} m, "
+ $"e = {e}, i = {i}, aPe = {aPe}, lAn = {lAn}");

return new Orbit(i, e, a, lAn, aPe, 0.0, utPeri, body);
}
Expand All @@ -190,17 +200,19 @@ private static Orbit createHyperbolicOrbit(CelestialBody body, double periapsis,
/// inside its parent body's sphere of influence at the current time.</exception>
private static Orbit patchToParent(Orbit oldOrbit) {
if (!needsSoITransition(oldOrbit)) {
throw new InvalidOperationException("Orbit is in the correct SoI; no patching needed.");
throw new InvalidOperationException(
$"Orbit is in the correct SoI ({oldOrbit.referenceBody}); no patching needed.");
}
if (oldOrbit.referenceBody.GetOrbitDriver() == null) {
throw new ArgumentException("Object does not orbit a body with a parent.", "oldOrbit");
throw new ArgumentException(
$"Object does not orbit a body with a parent, but {oldOrbit.referenceBody}.", "oldOrbit");
}
CelestialBody oldParent = oldOrbit.referenceBody;
CelestialBody newParent = oldParent.orbit.referenceBody;

double utSoi = getSoiCrossing(oldOrbit);
#if DEBUG
Debug.Log("Patching SoI transition from " + oldParent + " to " + newParent + "at UT " + utSoi);
Debug.Log($"Patching SoI transition from {oldParent} to {newParent} at UT {utSoi}");
#endif
// Need position/velocity relative to newParent, not oldParent or absolute
Vector3d xNewParent = oldOrbit.getRelativePositionAtUT(utSoi)
Expand Down Expand Up @@ -249,11 +261,11 @@ private static double getSoiCrossing(Orbit hyperbolic) {

double soi = hyperbolic.referenceBody.sphereOfInfluence;
if (Double.IsInfinity(soi) || Double.IsNaN(soi)) {
throw new ArgumentException("Body " + hyperbolic.referenceBody + " does not have a sphere of influence. ",
throw new ArgumentException($"Body {hyperbolic.referenceBody} does not have a sphere of influence.",
"hyperbolic");
}
if (hyperbolic.eccentricity < 1.0 && hyperbolic.ApR > soi) {
throw new ArgumentException("Orbit does not leave SoI.", "hyperbolic");
throw new ArgumentException($"Orbit {hyperbolic} does not leave SoI.", "hyperbolic");
}

double innerUT = hyperbolic.epoch - hyperbolic.ObTAtEpoch;
Expand Down Expand Up @@ -291,9 +303,8 @@ public string drawAsteroidType() {
try {
return AsteroidManager.drawAsteroidType(classRatios);
} catch (InvalidOperationException e) {
Debug.LogWarning("[CustomAsteroids]: Could not select asteroid class; reverting to default.");
Util.errorToPlayer(e, $"Could not select asteroid class for {name}.");
Debug.LogException(e);

return "PotatoRoid";
}
}
Expand Down
188 changes: 96 additions & 92 deletions src/AsteroidGroups/Population.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,114 +77,118 @@ public Orbit drawOrbit() {
}
#endif

try {
// Would like to only calculate this once, but I don't know for sure that this object will
// be initialized after FlightGlobals
CelestialBody orbitee = AsteroidManager.getPlanetByName(centralBody);
// Would like to only calculate this once, but I don't know for sure that this object will
// be initialized after FlightGlobals
CelestialBody orbitee = AsteroidManager.getPlanetByName(centralBody);

Debug.Log("[CustomAsteroids]: drawing orbit from " + name);
Debug.Log($"[CustomAsteroids]: drawing orbit from {name}");

// Properties with only one reasonable parametrization
double e = eccentricity.draw();
if (e < 0.0) {
throw new InvalidOperationException("[CustomAsteroids]: cannot have negative eccentricity (generated "
+ e + ")");
}
// Sign of inclination is redundant with 180-degree shift in longitude of ascending node
// So it's ok to just have positive inclinations
double i = inclination.draw();
double lAn = ascNode.draw(); // longitude of ascending node

// Position of periapsis
double aPe;
double peri = periapsis.draw(); // argument of periapsis
switch (periapsis.getParam()) {
case PeriRange.Type.Argument:
aPe = peri;
break;
case PeriRange.Type.Longitude:
aPe = peri - lAn;
break;
default:
throw new InvalidOperationException("[CustomAsteroids]: cannot describe periapsis position using type "
+ periapsis.getParam());
}
// Properties with only one reasonable parametrization
double e = wrappedDraw(eccentricity, name, "eccentricity");
if (e < 0.0) {
throw new InvalidOperationException(
$"Asteroids in group '{name}' cannot have negative eccentricity (generated {e})");
}
// Sign of inclination is redundant with 180-degree shift in longitude of ascending node
// So it's ok to just have positive inclinations
double i = wrappedDraw(inclination, name, "inclination");
double lAn = wrappedDraw(ascNode, name, "ascNode");

// Position of periapsis
double aPe;
double peri= wrappedDraw(periapsis, name, "periapsis");
switch (periapsis.getParam()) {
case PeriRange.Type.Argument:
aPe = peri;
break;
case PeriRange.Type.Longitude:
aPe = peri - lAn;
break;
default:
throw new InvalidOperationException(
$"Asteroids in group '{name}' cannot describe periapsis position using {periapsis.getParam()}");
}

// Semimajor axis
double a;
double size = orbitSize.draw();
switch (orbitSize.getParam()) {
case SizeRange.Type.SemimajorAxis:
a = size;
break;
case SizeRange.Type.Periapsis:
a = size / (1.0 - e);
break;
case SizeRange.Type.Apoapsis:
if (e > 1.0) {
throw new InvalidOperationException("[CustomAsteroids]: cannot constrain apoapsis on "
+ "unbound orbits (eccentricity " + e + ")");
}
a = size / (1.0 + e);
break;
default:
throw new InvalidOperationException("[CustomAsteroids]: cannot describe orbit size using type "
+ orbitSize.getParam());
// Semimajor axis
double a;
double size = wrappedDraw(orbitSize, name, "orbitSize");
switch (orbitSize.getParam()) {
case SizeRange.Type.SemimajorAxis:
a = size;
break;
case SizeRange.Type.Periapsis:
a = size / (1.0 - e);
break;
case SizeRange.Type.Apoapsis:
if (e > 1.0) {
throw new InvalidOperationException(
$"Asteroids in group '{name}' cannot constrain apoapsis on unbound orbits (eccentricity {e})");
}
a = size / (1.0 + e);
break;
default:
throw new InvalidOperationException(
$"Asteroids in group '{name}' cannot describe orbit size using {orbitSize.getParam()}");
}

// Mean anomaly at given epoch
double mEp, epoch;
double phase = orbitPhase.draw();
switch (orbitPhase.getParam()) {
case PhaseRange.PhaseType.MeanAnomaly:
// Mean anomaly is the ONLY orbital angle that needs to be given in radians
mEp = Math.PI / 180.0 * phase;
break;
case PhaseRange.PhaseType.MeanLongitude:
mEp = Math.PI / 180.0 * longToAnomaly(phase, i, aPe, lAn);
break;
default:
throw new InvalidOperationException("[CustomAsteroids]: cannot describe orbit position using type "
+ orbitSize.getParam());
}
switch (orbitPhase.getEpoch()) {
case PhaseRange.EpochType.GameStart:
epoch = 0.0;
break;
case PhaseRange.EpochType.Now:
epoch = Planetarium.GetUniversalTime();
break;
default:
throw new InvalidOperationException("[CustomAsteroids]: cannot describe orbit position using type "
+ orbitSize.getParam());
}
// Mean anomaly at given epoch
double mEp, epoch;
double phase = wrappedDraw(orbitPhase, name, "orbitPhase");
switch (orbitPhase.getParam()) {
case PhaseRange.PhaseType.MeanAnomaly:
// Mean anomaly is the ONLY orbital angle that needs to be given in radians
mEp = Math.PI / 180.0 * phase;
break;
case PhaseRange.PhaseType.MeanLongitude:
mEp = Math.PI / 180.0 * longToAnomaly(phase, i, aPe, lAn);
break;
default:
throw new InvalidOperationException(
$"Asteroids in group '{name}' cannot describe orbit position using type {orbitSize.getParam()}");
}
switch (orbitPhase.getEpoch()) {
case PhaseRange.EpochType.GameStart:
epoch = 0.0;
break;
case PhaseRange.EpochType.Now:
epoch = Planetarium.GetUniversalTime();
break;
default:
throw new InvalidOperationException(
$"Asteroids in group '{name}' cannot describe orbit position using type {orbitSize.getParam()}");
}

// Fix accidentally hyperbolic orbits
if (a * (1.0 - e) < 0.0) {
a = -a;
}
// Fix accidentally hyperbolic orbits
if (a * (1.0 - e) < 0.0) {
a = -a;
}

Debug.Log("[CustomAsteroids]: new orbit at " + a + " m, e = " + e + ", i = " + i
+ ", aPe = " + aPe + ", lAn = " + lAn + ", mEp = " + mEp + " at epoch " + epoch);
Debug.Log($"[CustomAsteroids]: new orbit at {a} m, e = {e}, i = {i}, "
+ $"aPe = {aPe}, lAn = {lAn}, mEp = {mEp} at epoch {epoch}");

// Does Orbit(...) throw exceptions?
Orbit newOrbit = new Orbit(i, e, a, lAn, aPe, mEp, epoch, orbitee);
frameTransform(newOrbit);
newOrbit.UpdateFromUT(Planetarium.GetUniversalTime());
// Does Orbit(...) throw exceptions?
Orbit newOrbit = new Orbit(i, e, a, lAn, aPe, mEp, epoch, orbitee);
frameTransform(newOrbit);
newOrbit.UpdateFromUT(Planetarium.GetUniversalTime());

return newOrbit;
return newOrbit;
}

private double wrappedDraw(ValueRange property, string group, string propertyName) {
try {
return property.draw();
} catch (ArgumentException e) {
throw new InvalidOperationException("[CustomAsteroids]: could not create orbit", e);
throw new InvalidOperationException (
$"Could not set orbital element '{propertyName}' for group '{group}'.", e);
}
}

public string drawAsteroidType() {
try {
return AsteroidManager.drawAsteroidType(classRatios);
} catch (InvalidOperationException e) {
Debug.LogWarning("[CustomAsteroids]: Could not select asteroid class; reverting to default.");
Util.errorToPlayer(e, $"Could not select asteroid class for group '{name}'.");
Debug.LogException(e);

return "PotatoRoid";
}
}
Expand Down Expand Up @@ -260,15 +264,15 @@ private void frameTransform(Orbit orbit) {
Vector3d v = orbit.getOrbitalVelocityAtUT(ut);

#if DEBUG
Debug.Log("Transforming orbit from frame " + plane);
Debug.Log($"Transforming orbit from frame {plane}");
#endif

Vector3d xNew = plane.toDefaultFrame(x);
Vector3d vNew = plane.toDefaultFrame(v);

orbit.UpdateFromStateVectors(xNew, vNew, orbit.referenceBody, ut);
} else if (refPlane != null) {
throw new InvalidOperationException("No such reference frame: " + refPlane);
throw new InvalidOperationException($"No such reference frame: {refPlane}");
}
}
}
Expand Down
Loading

0 comments on commit fcccd14

Please sign in to comment.