private static double ComputeVisibilityAndDistance(VesselRelayPersistence relay, Vessel targetVessel) { var result = relay.Vessel.HasLineOfSightWith(targetVessel, 0) ? Vector3d.Distance(relay.Vessel.GetVesselPos(), targetVessel.GetVesselPos()) : -1; return(result); }
public static IVesselRelayPersistence getVesselRelayPersistenceForVessel(Vessel vessel) { // find all active tranmitters configured for relay var relays = vessel.FindPartModulesImplementing <BeamedPowerTransmitter>().Where(m => m.IsRelay || m.mergingBeams).ToList(); if (relays.Count == 0) { return(null); } var relayPersistance = new VesselRelayPersistence(vessel); relayPersistance.IsActive = true; if (relayPersistance.IsActive) { return(relayPersistance); } foreach (var relay in relays) { var transmitData = relayPersistance.SupportedTransmitWavelengths.FirstOrDefault(m => m.wavelength == relay.wavelength); if (transmitData == null) { // Add guid if missing relay.partId = string.IsNullOrEmpty(relay.partId) ? Guid.NewGuid().ToString() : relay.partId; relayPersistance.SupportedTransmitWavelengths.Add(new WaveLengthData() { partId = new Guid(relay.partId), count = 1, apertureSum = relay.aperture, powerCapacity = relay.power_capacity, wavelength = relay.Wavelength, minWavelength = relay.minimumRelayWavelenght, maxWavelength = relay.maximumRelayWavelenght, isMirror = relay.isMirror, atmosphericAbsorption = relay.CombinedAtmosphericAbsorption }); } else { transmitData.count++; transmitData.apertureSum += relay.aperture; transmitData.powerCapacity += relay.power_capacity; } } relayPersistance.Aperture = relays.Average(m => m.aperture) * Approximate.Sqrt(relays.Count); relayPersistance.Diameter = relays.Average(m => m.diameter); relayPersistance.PowerCapacity = relays.Sum(m => m.getPowerCapacity()); relayPersistance.MinimumRelayWavelenght = relays.Min(m => m.minimumRelayWavelenght); relayPersistance.MaximumRelayWavelenght = relays.Max(m => m.maximumRelayWavelenght); return(relayPersistance); }
/// <summary> /// Returns transmitters which this vessel can connect /// </summary> /// <param name="maxHops">Maximum number of relays which can be used for connection to transmitter</param> public static IDictionary <VesselMicrowavePersistence, KeyValuePair <MicrowaveRoute, IList <VesselRelayPersistence> > > GetConnectedTransmitters(IBeamedPowerReceiver receiver, int maxHops = 25) { //these two dictionaries store transmitters and relays and best currently known route to them which is replaced if better one is found. var transmitterRouteDictionary = new Dictionary <VesselMicrowavePersistence, MicrowaveRoute>(); // stores all transmitter we can have a connection with var relayRouteDictionary = new Dictionary <VesselRelayPersistence, MicrowaveRoute>(); var transmittersToCheck = new List <VesselMicrowavePersistence>();//stores all transmiters to which we want to connect var recieverAtmosphericPresure = FlightGlobals.getStaticPressure(receiver.Vessel.GetVesselPos()) / 101.325; foreach (VesselMicrowavePersistence transmitter in BeamedPowerSources.instance.globalTransmitters.Values) { //ignore if no power or transmitter is on the same vessel if (transmitter.Vessel == receiver.Vessel) { //Debug.Log("[KSPI] : Transmitter vessel is equal to receiver vessel"); continue; } //first check for direct connection from current vessel to transmitters, will always be optimal if (!transmitter.HasPower) { //Debug.Log("[KSPI] : Transmitter vessel has no power available"); continue; } if (receiver.Vessel.HasLineOfSightWith(transmitter.Vessel)) { double facingFactor = ComputeFacingFactor(transmitter.Vessel, receiver); if (facingFactor <= 0) { continue; } var possibleWavelengths = new List <MicrowaveRoute>(); double distanceInMeter = ComputeDistance(receiver.Vessel, transmitter.Vessel); double transmitterAtmosphericPresure = FlightGlobals.getStaticPressure(transmitter.Vessel.GetVesselPos()) / 101.325; foreach (WaveLengthData wavelenghtData in transmitter.SupportedTransmitWavelengths) { if (wavelenghtData.wavelength.NotWithin(receiver.MaximumWavelength, receiver.MinimumWavelength)) { continue; } var spotsize = ComputeSpotSize(wavelenghtData, distanceInMeter, transmitter.Aperture, receiver.ApertureMultiplier); double distanceFacingEfficiency = ComputeDistanceFacingEfficiency(spotsize, facingFactor, receiver.Diameter, receiver.FacingEfficiencyExponent, receiver.SpotsizeNormalizationExponent); double atmosphereEfficency = GetAtmosphericEfficiency(transmitterAtmosphericPresure, recieverAtmosphericPresure, wavelenghtData.atmosphericAbsorption, distanceInMeter, receiver.Vessel, transmitter.Vessel); possibleWavelengths.Add(new MicrowaveRoute(distanceFacingEfficiency * atmosphereEfficency, distanceInMeter, facingFactor, spotsize, wavelenghtData)); } var mostEfficientWavelength = possibleWavelengths.Count == 0 ? null : possibleWavelengths.FirstOrDefault(m => m.Efficiency == possibleWavelengths.Max(n => n.Efficiency)); if (mostEfficientWavelength != null) { //store in dictionary that optimal route to this transmitter is direct connection, can be replaced if better route is found transmitterRouteDictionary[transmitter] = mostEfficientWavelength; } } // add all tranmitters that are not located on the recieving vessel transmittersToCheck.Add(transmitter); } //this algorithm processes relays in groups in which elements of the first group must be visible from receiver, //elements from the second group must be visible by at least one element from previous group and so on... var relaysToCheck = new List <VesselRelayPersistence>(); //relays which we have to check - all active relays will be here var currentRelayGroup = new List <KeyValuePair <VesselRelayPersistence, int> >(); //relays which are in line of sight, and we have not yet checked what they can see. Their index in relaysToCheck is also stored int relayIndex = 0; foreach (VesselRelayPersistence relay in BeamedPowerSources.instance.globalRelays.Values) { if (!relay.IsActive) { continue; } if (receiver.Vessel.HasLineOfSightWith(relay.Vessel)) { double facingFactor = ComputeFacingFactor(relay.Vessel, receiver); if (facingFactor <= 0) { continue; } double distanceInMeter = ComputeDistance(receiver.Vessel, relay.Vessel); double transmitterAtmosphericPresure = FlightGlobals.getStaticPressure(relay.Vessel.GetVesselPos()) / 101.325; var possibleWavelengths = new List <MicrowaveRoute>(); foreach (var wavelenghtData in relay.SupportedTransmitWavelengths) { if (wavelenghtData.maxWavelength < receiver.MinimumWavelength || wavelenghtData.minWavelength > receiver.MaximumWavelength) { continue; } double spotsize = ComputeSpotSize(wavelenghtData, distanceInMeter, relay.Aperture); double distanceFacingEfficiency = ComputeDistanceFacingEfficiency(spotsize, facingFactor, receiver.Diameter, receiver.FacingEfficiencyExponent, receiver.SpotsizeNormalizationExponent); double atmosphereEfficency = GetAtmosphericEfficiency(transmitterAtmosphericPresure, recieverAtmosphericPresure, wavelenghtData.atmosphericAbsorption, distanceInMeter, receiver.Vessel, relay.Vessel); possibleWavelengths.Add(new MicrowaveRoute(distanceFacingEfficiency * atmosphereEfficency, distanceInMeter, facingFactor, spotsize, wavelenghtData)); } var mostEfficientWavelength = possibleWavelengths.Count == 0 ? null : possibleWavelengths.FirstOrDefault(m => m.Efficiency == possibleWavelengths.Max(n => n.Efficiency)); if (mostEfficientWavelength != null) { //store in dictionary that optimal route to this relay is direct connection, can be replaced if better route is found relayRouteDictionary[relay] = mostEfficientWavelength; currentRelayGroup.Add(new KeyValuePair <VesselRelayPersistence, int>(relay, relayIndex)); } } relaysToCheck.Add(relay); relayIndex++; } int hops = 0; //number of hops between relays //pre-compute distances and visibility thus limiting number of checks to (Nr^2)/2 + NrNt +Nr + Nt if (hops < maxHops && transmittersToCheck.Any()) { double[,] relayToRelayDistances = new double[relaysToCheck.Count, relaysToCheck.Count]; double[,] relayToTransmitterDistances = new double[relaysToCheck.Count, transmittersToCheck.Count]; for (int i = 0; i < relaysToCheck.Count; i++) { var relayToCheck = relaysToCheck[i]; for (int j = i + 1; j < relaysToCheck.Count; j++) { double visibilityAndDistance = ComputeVisibilityAndDistance(relayToCheck, relaysToCheck[j].Vessel); relayToRelayDistances[i, j] = visibilityAndDistance; relayToRelayDistances[j, i] = visibilityAndDistance; } for (int t = 0; t < transmittersToCheck.Count; t++) { relayToTransmitterDistances[i, t] = ComputeVisibilityAndDistance(relayToCheck, transmittersToCheck[t].Vessel); } } HashSet <int> coveredRelays = new HashSet <int>(); //runs as long as there is any relay to which we can connect and maximum number of hops have not been breached while (hops < maxHops && currentRelayGroup.Any()) { var nextRelayGroup = new List <KeyValuePair <VesselRelayPersistence, int> >(); //will put every relay which is in line of sight of any relay from currentRelayGroup here foreach (var relayEntry in currentRelayGroup) //relays visible from receiver in first iteration, then relays visible from them etc.... { VesselRelayPersistence relayPersistance = relayEntry.Key; MicrowaveRoute relayRoute = relayRouteDictionary[relayPersistance]; // current best route for this relay double relayRouteFacingFactor = relayRoute.FacingFactor; // it's always facing factor from the beggining of the route double relayAtmosphericPresure = FlightGlobals.getStaticPressure(relayPersistance.Vessel.GetVesselPos()) / 101.325; for (int t = 0; t < transmittersToCheck.Count; t++)//check if this relay can connect to transmitters { double distanceInMeter = relayToTransmitterDistances[relayEntry.Value, t]; //it's >0 if it can see if (distanceInMeter <= 0) { continue; } VesselMicrowavePersistence transmitterToCheck = transmittersToCheck[t]; double newDistance = relayRoute.Distance + distanceInMeter;// total distance from receiver by this relay to transmitter double transmitterAtmosphericPresure = FlightGlobals.getStaticPressure(transmitterToCheck.Vessel.GetVesselPos()) / 101.325; var possibleWavelengths = new List <MicrowaveRoute>(); foreach (var transmitterWavelenghtData in transmitterToCheck.SupportedTransmitWavelengths) { if (transmitterWavelenghtData.wavelength.NotWithin(relayPersistance.MaximumRelayWavelenght, relayPersistance.MinimumRelayWavelenght)) { continue; } double spotsize = ComputeSpotSize(transmitterWavelenghtData, distanceInMeter, transmitterToCheck.Aperture); double distanceFacingEfficiency = ComputeDistanceFacingEfficiency(spotsize, 1, relayPersistance.Aperture); double atmosphereEfficency = GetAtmosphericEfficiency(transmitterAtmosphericPresure, relayAtmosphericPresure, transmitterWavelenghtData.atmosphericAbsorption, distanceInMeter, transmitterToCheck.Vessel, relayPersistance.Vessel); double efficiencyTransmitterToRelay = distanceFacingEfficiency * atmosphereEfficency; double efficiencyForRoute = efficiencyTransmitterToRelay * relayRoute.Efficiency; possibleWavelengths.Add(new MicrowaveRoute(efficiencyForRoute, newDistance, relayRouteFacingFactor, spotsize, transmitterWavelenghtData, relayPersistance)); } var mostEfficientWavelength = possibleWavelengths.Count == 0 ? null : possibleWavelengths.FirstOrDefault(m => m.Efficiency == possibleWavelengths.Max(n => n.Efficiency)); if (mostEfficientWavelength == null) { continue; } //this will return true if there is already a route to this transmitter MicrowaveRoute currentOptimalRoute; if (transmitterRouteDictionary.TryGetValue(transmitterToCheck, out currentOptimalRoute)) { if (currentOptimalRoute.Efficiency < mostEfficientWavelength.Efficiency) { //if route using this relay is better then replace the old route transmitterRouteDictionary[transmitterToCheck] = mostEfficientWavelength; } } else { //there is no other route to this transmitter yet known so algorithm puts this one as optimal transmitterRouteDictionary[transmitterToCheck] = mostEfficientWavelength; } } for (var r = 0; r < relaysToCheck.Count; r++) { VesselRelayPersistence nextRelay = relaysToCheck[r]; if (nextRelay == relayPersistance) { continue; } double distanceToNextRelay = relayToRelayDistances[relayEntry.Value, r]; if (distanceToNextRelay <= 0) { continue; } var possibleWavelengths = new List <MicrowaveRoute>(); double relayToNextRelayDistance = relayRoute.Distance + distanceToNextRelay; foreach (var transmitterWavelenghtData in relayPersistance.SupportedTransmitWavelengths) { if (transmitterWavelenghtData.maxWavelength < relayPersistance.MaximumRelayWavelenght || transmitterWavelenghtData.minWavelength > relayPersistance.MinimumRelayWavelenght) { continue; } double spotsize = ComputeSpotSize(transmitterWavelenghtData, distanceToNextRelay, relayPersistance.Aperture); double efficiencyByThisRelay = ComputeDistanceFacingEfficiency(spotsize, 1, relayPersistance.Aperture); double efficiencyForRoute = efficiencyByThisRelay * relayRoute.Efficiency; possibleWavelengths.Add(new MicrowaveRoute(efficiencyForRoute, relayToNextRelayDistance, relayRouteFacingFactor, spotsize, transmitterWavelenghtData, relayPersistance)); } MicrowaveRoute mostEfficientWavelength = possibleWavelengths.Count == 0 ? null : possibleWavelengths.FirstOrDefault(m => m.Efficiency == possibleWavelengths.Max(n => n.Efficiency)); if (mostEfficientWavelength != null) { MicrowaveRoute currentOptimalPredecessor; if (relayRouteDictionary.TryGetValue(nextRelay, out currentOptimalPredecessor)) //this will return true if there is already a route to next relay { //if route using this relay is better if (currentOptimalPredecessor.Efficiency < mostEfficientWavelength.Efficiency) { //we put it in dictionary as optimal relayRouteDictionary[nextRelay] = mostEfficientWavelength; } } else //there is no other route to this relay yet known so we put this one as optimal { relayRouteDictionary[nextRelay] = mostEfficientWavelength; } if (!coveredRelays.Contains(r)) { nextRelayGroup.Add(new KeyValuePair <VesselRelayPersistence, int>(nextRelay, r)); //in next iteration we will check what next relay can see coveredRelays.Add(r); } } } } currentRelayGroup = nextRelayGroup; //we don't have to check old relays so we just replace whole List hops++; } } //building final result var resultDictionary = new Dictionary <VesselMicrowavePersistence, KeyValuePair <MicrowaveRoute, IList <VesselRelayPersistence> > >(); foreach (var transmitterEntry in transmitterRouteDictionary) { VesselMicrowavePersistence vesselPersistance = transmitterEntry.Key; MicrowaveRoute microwaveRoute = transmitterEntry.Value; var relays = new Stack <VesselRelayPersistence>();//Last in, first out so relay visible from receiver will always be first VesselRelayPersistence relay = microwaveRoute.PreviousRelay; while (relay != null) { relays.Push(relay); relay = relayRouteDictionary[relay].PreviousRelay; } resultDictionary.Add(vesselPersistance, new KeyValuePair <MicrowaveRoute, IList <VesselRelayPersistence> >(microwaveRoute, relays.ToList())); } return(resultDictionary); }
public static IVesselRelayPersistence GetVesselRelayPersistenceForProtoVessel(Vessel vessel) { var relayVessel = new VesselRelayPersistence(vessel); int totalCount = 0; double totalDiameter = 0; double totalAperture = 0; double totalPowerCapacity = 0; double minimumRelayWavelength = 1; double maximumRelayWavelenght = 0; foreach (var protoPart in vessel.protoVessel.protoPartSnapshots) { foreach (var protoModule in protoPart.modules) { if (protoModule.moduleName != "MicrowavePowerTransmitter" && protoModule.moduleName != "PhasedArrayTransmitter" && protoModule.moduleName != "BeamedPowerLaserTransmitter") { continue; } bool inRelayMode = bool.Parse(protoModule.moduleValues.GetValue("relay")); bool isMergingBeams = false; if (protoModule.moduleValues.HasValue("mergingBeams")) { isMergingBeams = bool.Parse(protoModule.moduleValues.GetValue("mergingBeams")); } // filter on transmitters if (inRelayMode || isMergingBeams) { var wavelength = double.Parse(protoModule.moduleValues.GetValue("wavelength")); var isMirror = bool.Parse(protoModule.moduleValues.GetValue("isMirror")); var aperture = double.Parse(protoModule.moduleValues.GetValue("aperture")); var powerCapacity = double.Parse(protoModule.moduleValues.GetValue("power_capacity")); var diameter = protoModule.moduleValues.HasValue("diameter") ? double.Parse(protoModule.moduleValues.GetValue("diameter")) : aperture; totalCount++; totalAperture += aperture; totalDiameter += diameter; totalPowerCapacity += powerCapacity; var relayWavelenghtMin = double.Parse(protoModule.moduleValues.GetValue("minimumRelayWavelenght")); if (relayWavelenghtMin < minimumRelayWavelength) { minimumRelayWavelength = relayWavelenghtMin; } var relayWavelenghtMax = double.Parse(protoModule.moduleValues.GetValue("maximumRelayWavelenght")); if (relayWavelenghtMax > maximumRelayWavelenght) { maximumRelayWavelenght = relayWavelenghtMax; } var relayData = relayVessel.SupportedTransmitWavelengths.FirstOrDefault(m => m.wavelength == wavelength); if (relayData == null) { string partId = protoModule.moduleValues.GetValue("partId"); relayVessel.SupportedTransmitWavelengths.Add(new WaveLengthData() { partId = new Guid(partId), count = 1, apertureSum = aperture, powerCapacity = powerCapacity, wavelength = wavelength, minWavelength = relayWavelenghtMin, maxWavelength = relayWavelenghtMax, isMirror = isMirror, atmosphericAbsorption = double.Parse(protoModule.moduleValues.GetValue("atmosphericAbsorption")) }); } else { relayData.count++; relayData.apertureSum += aperture; relayData.powerCapacity += powerCapacity; } } } } relayVessel.Aperture = (totalAperture / totalCount) * Approximate.Sqrt(totalCount); relayVessel.Diameter = totalDiameter / totalCount; relayVessel.PowerCapacity = totalPowerCapacity; relayVessel.IsActive = totalCount > 0; relayVessel.MinimumRelayWavelenght = minimumRelayWavelength; relayVessel.MaximumRelayWavelenght = maximumRelayWavelenght; return(relayVessel); }
public static IVesselRelayPersistence getVesselRelayPersistanceForProtoVessel(Vessel vessel) { var relayVessel = new VesselRelayPersistence(vessel); int totalCount = 0; double totalAperture = 0; double totalPowerCapacity = 0; double minimumRelayWavelength = 1; double maximumRelayWavelenght = 0; foreach (var protopart in vessel.protoVessel.protoPartSnapshots) { foreach (var protomodule in protopart.modules) { if (protomodule.moduleName != "MicrowavePowerTransmitter") { continue; } bool inRelayMode = bool.Parse(protomodule.moduleValues.GetValue("relay")); bool isMergingBeams = false; if (protomodule.moduleValues.HasValue("mergingBeams")) { try { bool.TryParse(protomodule.moduleValues.GetValue("mergingBeams"), out isMergingBeams); } catch (Exception e) { UnityEngine.Debug.LogError("[KSPI]: Exception while reading mergingBeams" + e.Message); } } // filter on transmitters if (inRelayMode || isMergingBeams) { var wavelength = double.Parse(protomodule.moduleValues.GetValue("wavelength")); var isMirror = bool.Parse(protomodule.moduleValues.GetValue("isMirror")); var aperture = double.Parse(protomodule.moduleValues.GetValue("aperture")); var powerCapacity = double.Parse(protomodule.moduleValues.GetValue("power_capacity")); totalCount++; totalAperture += aperture; totalPowerCapacity += powerCapacity; var relayWavelenghtMin = double.Parse(protomodule.moduleValues.GetValue("minimumRelayWavelenght")); if (relayWavelenghtMin < minimumRelayWavelength) { minimumRelayWavelength = relayWavelenghtMin; } var relayWavelenghtMax = double.Parse(protomodule.moduleValues.GetValue("maximumRelayWavelenght")); if (relayWavelenghtMax > maximumRelayWavelenght) { maximumRelayWavelenght = relayWavelenghtMax; } var relayData = relayVessel.SupportedTransmitWavelengths.FirstOrDefault(m => m.wavelength == wavelength); if (relayData == null) { string partId = protomodule.moduleValues.GetValue("partId"); relayVessel.SupportedTransmitWavelengths.Add(new WaveLengthData() { partId = new Guid(partId), count = 1, apertureSum = aperture, powerCapacity = powerCapacity, wavelength = wavelength, minWavelength = relayWavelenghtMin, maxWavelength = relayWavelenghtMax, isMirror = isMirror, atmosphericAbsorption = double.Parse(protomodule.moduleValues.GetValue("atmosphericAbsorption")) }); } else { relayData.count++; relayData.apertureSum += aperture; relayData.powerCapacity += powerCapacity; } } } } relayVessel.Aperture = totalAperture; relayVessel.PowerCapacity = totalPowerCapacity; relayVessel.IsActive = totalCount > 0; relayVessel.MinimumRelayWavelenght = minimumRelayWavelength; relayVessel.MaximumRelayWavelenght = maximumRelayWavelenght; return(relayVessel); }