using System;
using System.Collections.Generic;
using RemoteTech.RangeModel;
namespace RemoteTech
{
public class NetworkFeedback
{
/// Returns the position of a target identified only by its Guid
/// An absolute world coordinate position.
/// The item whose position is desired. May be either a satellite
/// or a celestial body
/// Throws System.ArgumentException if target or network does not exist.
public static Vector3d targetPosition(Guid target) {
if (RTCore.Instance != null && RTCore.Instance.Network != null &&
target != Guid.Empty) {
ISatellite targetSat = RTCore.Instance.Network[target];
if (targetSat != null) {
return targetSat.Position;
}
try {
CelestialBody targetPlanet = RTCore.Instance.Network.Planets[target];
return targetPlanet.position;
} catch (KeyNotFoundException) {}
}
throw new System.ArgumentException("No such Guid found", "target");
}
/// Returns the SoI of a target identified only by its Guid
/// If target refers to a celestial body, returns that body. If target refers
/// to an ISatellite, returns the body whose SoI currently contains the ISatellite.
/// The item whose position is desired. May be either a satellite
/// or a celestial body.
/// Throws System.ArgumentException if target or network does not exist.
public static CelestialBody targetBody(Guid target) {
if (RTCore.Instance != null && RTCore.Instance.Network != null &&
target != Guid.Empty) {
ISatellite targetSat = RTCore.Instance.Network[target];
if (targetSat != null) {
return targetSat.Body;
}
try {
CelestialBody targetPlanet = RTCore.Instance.Network.Planets[target];
return targetPlanet;
} catch (KeyNotFoundException) {}
}
throw new System.ArgumentException("No such Guid found", "target");
}
/// Counts the number of ISatellites that are in the antenna cone and in range.
/// The number of reachable satellites.
/// If antenna does not have a cone, returns 0.
/// The antenna whose cone must be tested.
/// The object the cone is pointed at.
public static int countInCone(IAntenna antenna, Guid target) {
if (antenna.Dish <= 0.0 || antenna.CosAngle >= 1.0) {
return 0;
}
try {
Vector3d myPos = RTCore.Instance.Network[antenna.Guid].Position;
Vector3d targetDir = (targetPosition(target) - myPos).normalized;
CelestialBody myBody = targetBody(target);
int count = 0;
foreach (ISatellite sat in RTCore.Instance.Satellites) {
Vector3d satDir = (sat.Position - myPos).normalized;
if (Vector3d.Distance(myPos, sat.Position) <= antenna.Dish // in range
&& Vector3d.Dot(targetDir, satDir) >= antenna.CosAngle // in cone
&& sat.Body == myBody) // in target SoI... remove later
count++;
}
return count;
} catch (ArgumentException) {
return 0;
} catch (NullReferenceException) {
return 0;
}
}
/// Tests whether an antenna can connect to a target
/// The range to the target, or a diagnostic error message. Returns the
/// empty string if target is invalid.
/// The antenna attempting to make a connection.
/// The Guid to which it is trying to connect.
public static KeyValuePair tryConnection(IAntenna antenna, Guid target) {
String status = "ok";
// What kind of target?
if (RTCore.Instance != null && RTCore.Instance.Network != null &&
target != Guid.Empty && target != NetworkManager.ActiveVesselGuid) {
bool warning = false, error = false;
ISatellite mySat = RTCore.Instance.Network[antenna.Guid];
if (mySat == null)
return new KeyValuePair("", UnityEngine.Color.white);
List conditions = new List();
// Most probably a satellite
ISatellite targetSat = RTCore.Instance.Network[target];
if (targetSat != null) {
if (!RangeModelExtensions.HasLineOfSightWith(mySat, targetSat)) {
status = "No line of sight";
error = true;
}
double dist = RangeModelExtensions.DistanceTo(mySat, targetSat);
// Only standard model supported for now, RangeModel isn't designed for this problem
double maxDist = Math.Max(antenna.Omni, antenna.Dish);
conditions.Add("Current distance:" + RTUtil.FormatSI(dist, "m"));
conditions.Add("Antenna range:" + RTUtil.FormatSI(maxDist, "m"));
if (dist > maxDist) {
status = "Target not in range";
error = true;
}
}
try {
CelestialBody targetPlanet = RTCore.Instance.Network.Planets[target];
double dist = Vector3d.Distance(mySat.Position, targetPlanet.position);
double maxDist = Math.Max(antenna.Omni, antenna.Dish);
double spread = 2.0 * dist * Math.Sqrt(1-antenna.CosAngle*antenna.CosAngle);
int numTargets = countInCone(antenna, target);
if (spread < 2.0 * targetPlanet.Radius) {
// WHAT does this info?
// conditions.Add("Small Cone");
warning = true;
}
conditions.Add("Current distance:"+RTUtil.FormatSI(dist, "m"));
conditions.Add("Antenna range:" + RTUtil.FormatSI(maxDist, "m"));
if (dist <= maxDist) {
conditions.Add(String.Format("Info:{0} beam covers {1} targets)",
RTUtil.FormatSI(spread, "m"),
numTargets
));
} else {
status = "Target not in range";
error = true;
}
if (numTargets <= 0) {
warning = true;
}
} catch (KeyNotFoundException) {}
conditions.Add("Status:" + status);
return new KeyValuePair(
String.Join("; ", conditions.ToArray()),
error ? UnityEngine.Color.red : (warning ? UnityEngine.Color.yellow : UnityEngine.Color.white)
);
}
// Default behavior
return new KeyValuePair("", UnityEngine.Color.white);
}
}
}