/// <summary> /// Caches the waypoint data. /// </summary> public static void CacheWaypointData() { if (lastCacheUpdate == UnityEngine.Time.fixedTime) { return; } lastCacheUpdate = UnityEngine.Time.fixedTime; bool changed = false; // Add new waypoints foreach (Waypoint w in WaypointManager.AllWaypoints()) { if (w != null && w.isNavigatable) { WaypointData wpd; // Update values that are only cached once if (!waypointData.ContainsKey(w)) { wpd = new WaypointData(); wpd.waypoint = w; wpd.celestialBody = Util.GetBody(w.celestialName); // Shouldn't normally happens, but who knows (Util.GetBody will throw a warning) if (wpd.celestialBody == null) { continue; } // Figure out the terrain height wpd.waypoint.height = Util.WaypointHeight(w, wpd.celestialBody); // Add to waypoint data waypointData[w] = wpd; changed = true; } else { wpd = waypointData[w]; } // Update values that change every frame wpd.lastChecked = UnityEngine.Time.fixedTime; if (FlightGlobals.ActiveVessel != null && wpd.celestialBody == FlightGlobals.ActiveVessel.mainBody) { wpd.distanceToActive = Util.GetDistanceToWaypoint(wpd); // Get information about whether the waypoint is occluded Vector3 pos = wpd.celestialBody.GetWorldSurfacePosition(wpd.waypoint.latitude, wpd.waypoint.longitude, wpd.waypoint.height + wpd.waypoint.altitude); wpd.isOccluded = IsOccluded(wpd.celestialBody, FlightCamera.fetch.transform.position, pos, wpd.waypoint.height + wpd.waypoint.altitude); Vector3 vHeading = FlightGlobals.ActiveVessel.transform.up; double vesselLat = FlightGlobals.ActiveVessel.latitude / 180.0 * Math.PI; double vesselLon = FlightGlobals.ActiveVessel.longitude / 180.0 * Math.PI; double wpLat = wpd.waypoint.latitude / 180.0 * Math.PI; double wpLon = wpd.waypoint.longitude / 180.0 * Math.PI; double y = Math.Sin(wpLon - vesselLon) * Math.Cos(wpLat); double x = (Math.Cos(vesselLat) * Math.Sin(wpLat)) - (Math.Sin(vesselLat) * Math.Cos(wpLat) * Math.Cos(wpLon - vesselLon)); double requiredHeading = Math.Atan2(y, x) * 180.0 / Math.PI; wpd.heading = (requiredHeading + 360.0) % 360.0; } } } // Remove unused waypoints foreach (KeyValuePair <Waypoint, WaypointData> p in waypointData.Where(p => p.Value.lastChecked != UnityEngine.Time.fixedTime).ToArray()) { changed = true; waypointData.Remove(p.Key); } if (changed || customWaypoints.waypointByContract.Count != WaypointManager.customWaypoints.Count()) { // Clear the by contract list foreach (ContractContainer cc in contractMap.Values) { cc.waypointByContract.Clear(); } customWaypoints.waypointByContract.Clear(); // Rebuild the by contract list foreach (WaypointData wpd in waypointData.Values) { if (wpd.waypoint.contractReference != null) { if (!contractMap.ContainsKey(wpd.waypoint.contractReference.ContractID)) { contractMap[wpd.waypoint.contractReference.ContractID] = new ContractContainer(wpd.waypoint.contractReference); } contractMap[wpd.waypoint.contractReference.ContractID].waypointByContract.Add(wpd); } else { customWaypoints.waypointByContract.Add(wpd); } } // Remove any unused contracts foreach (ContractContainer cc in contractMap.Values.ToList()) { if (cc.waypointByContract.Count == 0) { contractMap.Remove(cc.contract.ContractID); } } // Rebuild the by Celestial Body list waypointByBody.Clear(); foreach (WaypointData wpd in waypointData.Values) { if (!waypointByBody.ContainsKey(wpd.celestialBody)) { waypointByBody[wpd.celestialBody] = new List <WaypointData>(); } waypointByBody[wpd.celestialBody].Add(wpd); } } }