/// <summary> /// Callback used by ConfigNode.LoadObjectFromConfig(). Ensures vectors in config file are /// properly interpreted. Warning: Class invariants should not be assumed to hold true prior /// to calling this method. /// </summary> /// /// <remarks><c>this.normVector</c> and <c>this.refVector</c> must be initialized (non-zero) /// prior to method invocation.</remarks> /// /// <exception cref="TypeInitializationException">Thrown if one of the vectors has zero /// length, or if the two vectors are aligned.</exception> public void PersistenceLoad() { try { if (normVector.magnitude < 1e-8) { throw new InvalidOperationException( Localizer.Format("#autoLOC_CustomAsteroids_ErrorRefVectorNoZero", name)); } // Only the component in the plane is useful Vector3d trueReference = refVector - Vector3d.Project(refVector, normVector); if (trueReference.magnitude < 1e-8) { throw new InvalidOperationException( Localizer.Format("#autoLOC_CustomAsteroids_ErrorRefVectorDegenerate", name)); } Quaternion q = Quaternion.FromToRotation(Planetarium.up.xzy, normVector); // FromToRotation can give unintuitive rotations, so check reference direction carefully float theta = (float)Vector3d.Angle(q * Planetarium.right.xzy, trueReference); // Unity documentation gives wrong order of operations; u*v means // "rotate by v, then rotate by u". impl = new SimplePlane(id, Quaternion.AngleAxis(theta, normVector) * q); } catch (ArgumentException e) { throw new TypeInitializationException("Starstrider42.CustomAsteroids.RefVectors", e); } }
internal RefVectors() { id = "invalid"; normVector = Vector3d.zero; refVector = Vector3d.zero; impl = null; }
internal RefAsOrbit() { id = "invalid"; rawLongAscNode = "0"; rawInclination = "0"; rawArgReference = "0"; impl = null; }
/// <summary> /// Callback used by ConfigNode.LoadObjectFromConfig(). Ensures that any abstract entries /// in the config file are properly interpreted. Warning: Class invariants should not be /// assumed to hold true prior to calling this method. /// </summary> /// /// <remarks><c>this.rawLongAscNode</c>, <c>this.rawInclination</c>, and /// <c>this.rawArgReference</c> must contain a representation of the desired object value /// prior to method invocation.</remarks> /// /// <exception cref="TypeInitializationException">Thrown if the ConfigNode could not be /// interpreted as a set of floating-point values. The program will be in a consistent state /// in the event of an exception.</exception> public void PersistenceLoad() { try { float longAscNode = (float)ValueRange.parseOrbitalElement(rawLongAscNode); float inclination = (float)ValueRange.parseOrbitalElement(rawInclination); float argReference = (float)ValueRange.parseOrbitalElement(rawArgReference); // Rotations are always around planetarium axes, so treat as extrinsic // Rotate first by argReference, then by inclination, then by longAscNode // Unity documentation gives the wrong order of operations Quaternion q = Quaternion.Euler(0, 0, longAscNode) * Quaternion.Euler(inclination, 0, argReference); impl = new SimplePlane(id, q); } catch (ArgumentException e) { throw new TypeInitializationException("Starstrider42.CustomAsteroids.RefAsOrbit", e); } }