/// <summary> /// Returns transmitters which to which this vessel can connect, route efficiency and relays used for each one. /// </summary> /// <param name="maxHops">Maximum number of relays which can be used for connection to transmitter</param> protected IDictionary<VesselMicrowavePersistence, KeyValuePair<double, IEnumerable<VesselRelayPersistence>>> GetConnectedTransmitters(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>(); var relayRouteDictionary = new Dictionary<VesselRelayPersistence, MicrowaveRoute>(); var transmittersToCheck = new List<VesselMicrowavePersistence>();//stores all transmiters to which we want to connect foreach (VesselMicrowavePersistence transmitter in vmps) { //first check for direct connection from current vessel to transmitters, will always be optimal if (transmitter.getAvailablePower() > 0) { //ignore if no power or transmitter is on the same vessel if (!isInlineReceiver || transmitter.getVessel() != vessel) { if (lineOfSightTo(transmitter.getVessel())) { double distance = ComputeDistance(vessel, transmitter.getVessel()); double facingFactor = ComputeFacingFactor(transmitter.getVessel()); double efficiency = ComputeTransmissionEfficiency(distance, facingFactor); transmitterRouteDictionary[transmitter] = new MicrowaveRoute(efficiency, distance, facingFactor); //store in dictionary that optimal route to this transmitter is direct connection, can be replaced if better route is found } 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 vrps) { if (relay.isActive()) { if (lineOfSightTo(relay.getVessel())) { double distance = ComputeDistance(vessel, relay.getVessel()); double facingFactor = ComputeFacingFactor(relay.getVessel()); double efficiency = ComputeTransmissionEfficiency(distance, facingFactor); relayRouteDictionary[relay] = new MicrowaveRoute(efficiency, distance, facingFactor);//store in dictionary that optimal route to this relay is direct connection, can be replaced if better route is found 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 relay = relaysToCheck[i]; for (int j = i + 1; j < relaysToCheck.Count; j++) { double visibilityAndDistance = ComputeVisibilityAndDistance(relay, relaysToCheck[j].getVessel()); relayToRelayDistances[i, j] = visibilityAndDistance; relayToRelayDistances[j, i] = visibilityAndDistance; } for (int t = 0; t < transmittersToCheck.Count; t++) { relayToTransmitterDistances[i, t] = ComputeVisibilityAndDistance(relay, transmittersToCheck[t]. getVessel()); } } 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.... { var relay = relayEntry.Key; MicrowaveRoute relayRoute = relayRouteDictionary[relay];// current best route for this relay double relayRouteFacingFactor = relayRoute.FacingFactor;// it's always facing factor from the beggining of the route for (int t = 0; t < transmittersToCheck.Count; t++)//check if this relay can connect to transmitters { var transmitter = transmittersToCheck[t]; double transmitterDistance = relayToTransmitterDistances[relayEntry.Value, t]; if (transmitterDistance > 0)//it's >0 if it can see { double newDistance = relayRoute.Distance + transmitterDistance;// total distance from receiver by this relay to transmitter double efficiencyByThisRelay = ComputeTransmissionEfficiency(newDistance, relayRouteFacingFactor);//efficiency MicrowaveRoute currentOptimalRoute; //this will return true if there is already a route to this transmitter if (transmitterRouteDictionary.TryGetValue(transmitter, out currentOptimalRoute)) { if (currentOptimalRoute.Efficiency < efficiencyByThisRelay) //if route using this relay is better then replace the old route transmitterRouteDictionary[transmitter] = new MicrowaveRoute(efficiencyByThisRelay, newDistance, relayRouteFacingFactor, relay); } else { //there is no other route to this transmitter yet known so algorithm puts this one as optimal transmitterRouteDictionary[transmitter] = new MicrowaveRoute(efficiencyByThisRelay, newDistance, relayRouteFacingFactor, relay); } } } for (int r = 0; r < relaysToCheck.Count; r++) { var nextRelay = relaysToCheck[r]; if (nextRelay == relay) continue; double distanceToNextRelay = relayToRelayDistances[relayEntry.Value, r]; if (distanceToNextRelay > 0) //any relay which is in LOS of this relay { double relayToNextRelayDistance = relayRoute.Distance + distanceToNextRelay; double efficiencyByThisRelay = ComputeTransmissionEfficiency(relayToNextRelayDistance, relayRouteFacingFactor); MicrowaveRoute currentOptimalPredecessor; if (relayRouteDictionary.TryGetValue(nextRelay, out currentOptimalPredecessor)) //this will return true if there is already a route to next relay { if (currentOptimalPredecessor.Efficiency < efficiencyByThisRelay) //if route using this relay is better relayRouteDictionary[nextRelay] = new MicrowaveRoute(efficiencyByThisRelay, relayToNextRelayDistance, relayRoute.FacingFactor, relay); //we put it in dictionary as optimal } else //there is no other route to this relay yet known so we put this one as optimal { relayRouteDictionary[nextRelay] = new MicrowaveRoute(efficiencyByThisRelay, relayToNextRelayDistance, relayRoute.FacingFactor, relay); } 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<double, IEnumerable<VesselRelayPersistence>>>(); foreach (var transmitterEntry in transmitterRouteDictionary) { Stack<VesselRelayPersistence> relays = new Stack<VesselRelayPersistence>();//Last in, first out so relay visible from receiver will always be first VesselRelayPersistence relay = transmitterEntry.Value.PreviousRelay; while (relay != null) { relays.Push(relay); relay = relayRouteDictionary[relay].PreviousRelay; } resultDictionary.Add(transmitterEntry.Key, new KeyValuePair<double, IEnumerable<VesselRelayPersistence>>(transmitterEntry.Value.Efficiency, relays)); } return resultDictionary; //connectedTransmitters; }
/// <summary> /// Returns transmitters which to which this vessel can connect, route efficiency and relays used for each one. /// </summary> /// <param name="maxHops">Maximum number of relays which can be used for connection to transmitter</param> protected IDictionary <VesselMicrowavePersistence, KeyValuePair <double, IEnumerable <VesselRelayPersistence> > > GetConnectedTransmitters(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>(); var relayRouteDictionary = new Dictionary <VesselRelayPersistence, MicrowaveRoute>(); var transmittersToCheck = new List <VesselMicrowavePersistence>();//stores all transmiters to which we want to connect foreach (VesselMicrowavePersistence transmitter in MicrowaveSources.instance.transmitters.Values) { //first check for direct connection from current vessel to transmitters, will always be optimal if (transmitter.getAvailablePower() > 0) { //ignore if no power or transmitter is on the same vessel if (!isInlineReceiver || transmitter.getVessel() != vessel) { if (lineOfSightTo(transmitter.getVessel())) { double distance = ComputeDistance(vessel, transmitter.getVessel()); double facingFactor = ComputeFacingFactor(transmitter.getVessel()); double efficiency = ComputeTransmissionEfficiency(distance, facingFactor); transmitterRouteDictionary[transmitter] = new MicrowaveRoute(efficiency, distance, facingFactor); //store in dictionary that optimal route to this transmitter is direct connection, can be replaced if better route is found } 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 MicrowaveSources.instance.relays.Values) { if (relay.isActive()) { if (lineOfSightTo(relay.getVessel())) { double distance = ComputeDistance(vessel, relay.getVessel()); double facingFactor = ComputeFacingFactor(relay.getVessel()); double efficiency = ComputeTransmissionEfficiency(distance, facingFactor); relayRouteDictionary[relay] = new MicrowaveRoute(efficiency, distance, facingFactor);//store in dictionary that optimal route to this relay is direct connection, can be replaced if better route is found 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 relay = relaysToCheck[i]; for (int j = i + 1; j < relaysToCheck.Count; j++) { double visibilityAndDistance = ComputeVisibilityAndDistance(relay, relaysToCheck[j].getVessel()); relayToRelayDistances[i, j] = visibilityAndDistance; relayToRelayDistances[j, i] = visibilityAndDistance; } for (int t = 0; t < transmittersToCheck.Count; t++) { relayToTransmitterDistances[i, t] = ComputeVisibilityAndDistance(relay, transmittersToCheck[t]. getVessel()); } } 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.... { var relay = relayEntry.Key; MicrowaveRoute relayRoute = relayRouteDictionary[relay]; // current best route for this relay double relayRouteFacingFactor = relayRoute.FacingFactor; // it's always facing factor from the beggining of the route for (int t = 0; t < transmittersToCheck.Count; t++) //check if this relay can connect to transmitters { var transmitter = transmittersToCheck[t]; double transmitterDistance = relayToTransmitterDistances[relayEntry.Value, t]; if (transmitterDistance > 0) //it's >0 if it can see { double newDistance = relayRoute.Distance + transmitterDistance; // total distance from receiver by this relay to transmitter double efficiencyByThisRelay = ComputeTransmissionEfficiency(newDistance, relayRouteFacingFactor); //efficiency MicrowaveRoute currentOptimalRoute; //this will return true if there is already a route to this transmitter if (transmitterRouteDictionary.TryGetValue(transmitter, out currentOptimalRoute)) { if (currentOptimalRoute.Efficiency < efficiencyByThisRelay) { //if route using this relay is better then replace the old route transmitterRouteDictionary[transmitter] = new MicrowaveRoute(efficiencyByThisRelay, newDistance, relayRouteFacingFactor, relay); } } else { //there is no other route to this transmitter yet known so algorithm puts this one as optimal transmitterRouteDictionary[transmitter] = new MicrowaveRoute(efficiencyByThisRelay, newDistance, relayRouteFacingFactor, relay); } } } for (int r = 0; r < relaysToCheck.Count; r++) { var nextRelay = relaysToCheck[r]; if (nextRelay == relay) { continue; } double distanceToNextRelay = relayToRelayDistances[relayEntry.Value, r]; if (distanceToNextRelay > 0) //any relay which is in LOS of this relay { double relayToNextRelayDistance = relayRoute.Distance + distanceToNextRelay; double efficiencyByThisRelay = ComputeTransmissionEfficiency(relayToNextRelayDistance, relayRouteFacingFactor); MicrowaveRoute currentOptimalPredecessor; if (relayRouteDictionary.TryGetValue(nextRelay, out currentOptimalPredecessor)) //this will return true if there is already a route to next relay { if (currentOptimalPredecessor.Efficiency < efficiencyByThisRelay) { //if route using this relay is better relayRouteDictionary[nextRelay] = new MicrowaveRoute(efficiencyByThisRelay, relayToNextRelayDistance, relayRoute.FacingFactor, relay); } //we put it in dictionary as optimal } else //there is no other route to this relay yet known so we put this one as optimal { relayRouteDictionary[nextRelay] = new MicrowaveRoute(efficiencyByThisRelay, relayToNextRelayDistance, relayRoute.FacingFactor, relay); } 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 <double, IEnumerable <VesselRelayPersistence> > >(); foreach (var transmitterEntry in transmitterRouteDictionary) { Stack <VesselRelayPersistence> relays = new Stack <VesselRelayPersistence>();//Last in, first out so relay visible from receiver will always be first VesselRelayPersistence relay = transmitterEntry.Value.PreviousRelay; while (relay != null) { relays.Push(relay); relay = relayRouteDictionary[relay].PreviousRelay; } resultDictionary.Add(transmitterEntry.Key, new KeyValuePair <double, IEnumerable <VesselRelayPersistence> >(transmitterEntry.Value.Efficiency, relays)); } return(resultDictionary); //connectedTransmitters; }