//Draw the orbit overlay internal static void drawOrbit(Rect maprect, SCANmap map, Vessel vessel, CelestialBody body) { if (vessel == null) return; if (vessel.mainBody != body) return; int eqh = 16; if (vessel.LandedOrSplashed) return; bool lite = maprect.width < 400; Orbit o = vessel.orbit; double startUT = Planetarium.GetUniversalTime(); double UT = startUT; int steps = 80; // increase for neater lines, decrease for better speed indication bool ath = false; if (vessel.mainBody.atmosphere) { if (vessel.mainBody.atmosphereDepth >= vessel.altitude) { ath = true; } } Rect r = new Rect(0, 0, 70f, 50f); Color col; // project the last and the current orbital period onto the map for (int i = -steps; i < steps; ++i) { if (i < 0) UT = startUT - (steps + i) * (o.period / steps); else UT = startUT + i * o.period * 1f / steps; if (double.IsNaN(UT)) continue; if (UT < o.StartUT && o.StartUT != startUT) continue; if (UT > o.EndUT) continue; if (double.IsNaN(o.getObtAtUT(UT))) continue; Vector3d pos = o.getPositionAtUT(UT); double rotation = 0; if (vessel.mainBody.rotates) { rotation = (360 * ((UT - startUT) / vessel.mainBody.rotationPeriod)) % 360; } double alt = (vessel.mainBody.GetAltitude(pos)); if (alt < 0) { if (i < 0) { i = 0; continue; } break; } double lo = (vessel.mainBody.GetLongitude(pos) - rotation); double la = (vessel.mainBody.GetLatitude(pos)); double lon = (map.projectLongitude(lo, la) + 180) % 360; double lat = (map.projectLatitude(lo, la) + 90) % 180; lat = map.scaleLatitude(lat); lon = map.scaleLongitude(lon); if (lat < 0 || lon < 0 || lat > 180 || lon > 360) continue; lon = lon * maprect.width / 360f; lat = maprect.height - lat * maprect.height / 180f; r.x = maprect.x + (float)lon; r.y = maprect.y + (float)lat; col = palette.cb_skyBlue; if (i < 0) { col = palette.cb_orange; } else { if (vessel.mainBody.atmosphere) { if (vessel.mainBody.atmosphereDepth >= alt) { if (!ath) { ath = true; // do something when it flips? } col = palette.cb_reddishPurple; } } } SCANicon.drawOrbitIcon((int)r.x, (int)r.y, SCANicon.OrbitIcon.Planet, col, 8, false); } // show apoapsis and periapsis if (o.ApA > 0 && mapPosAtT(maprect, map, ref r, vessel, o, o.timeToAp, startUT)) { SCANicon.drawOrbitIcon((int)r.x, (int)r.y, SCANicon.OrbitIcon.Ap, palette.cb_skyBlue, 32, true); r.x += 24; r.y -= 12; if (!lite) drawLabel(r, o.ApA.ToString("N0"), true, true, true); } if (o.PeA > 0 && mapPosAtT(maprect, map, ref r, vessel, o, o.timeToPe, startUT)) { SCANicon.drawOrbitIcon((int)r.x, (int)r.y, SCANicon.OrbitIcon.Pe, palette.cb_skyBlue, 32, true); r.x += 24; r.y -= 12; if (!lite) drawLabel(r, o.PeA.ToString("N0"), true, true, true); } if (lite) return; // show first maneuver node if (vessel.patchedConicSolver != null) { if (vessel.patchedConicSolver.maneuverNodes.Count > 0) { ManeuverNode n = vessel.patchedConicSolver.maneuverNodes[0]; if (n.patch == vessel.orbit && n.nextPatch != null && n.nextPatch.activePatch && n.UT > startUT - o.period && mapPosAtT(maprect, map, ref r, vessel, o, n.UT - startUT, startUT)) { col = palette.cb_reddishPurple; if (SCANcontroller.controller.colours != 1) col = palette.xkcd_PurplyPink; SCANicon.drawOrbitIcon((int)r.x, (int)r.y, SCANicon.OrbitIcon.ManeuverNode, col, 32, true); Orbit nuo = n.nextPatch; for (int i = 0; i < steps; ++i) { double T = n.UT - startUT + i * nuo.period / steps; if (T + startUT > nuo.EndUT) break; if (mapPosAtT(maprect, map, ref r, vessel, nuo, T, startUT)) { SCANicon.drawOrbitIcon((int)r.x, (int)r.y, SCANicon.OrbitIcon.Planet, col, 8, false); } } if (nuo.patchEndTransition == Orbit.PatchTransitionType.ESCAPE) { SCANicon.drawOrbitIcon((int)r.x, (int)r.y, SCANicon.OrbitIcon.Exit, col, 32, true); } else if (nuo.patchEndTransition == Orbit.PatchTransitionType.ENCOUNTER) { SCANicon.drawOrbitIcon((int)r.x, (int)r.y, SCANicon.OrbitIcon.Encounter, col, 32, true); } if (nuo.timeToAp > 0 && n.UT + nuo.timeToAp < nuo.EndUT && mapPosAtT(maprect, map, ref r, vessel, nuo, n.UT - startUT + nuo.timeToAp, startUT)) { SCANicon.drawOrbitIcon((int)r.x, (int)r.y, SCANicon.OrbitIcon.Ap, col, 32, true); } if (nuo.timeToPe > 0 && n.UT + nuo.timeToPe < nuo.EndUT && mapPosAtT(maprect, map, ref r, vessel, nuo, n.UT - startUT + nuo.timeToPe, startUT)) { SCANicon.drawOrbitIcon((int)r.x, (int)r.y, SCANicon.OrbitIcon.Pe, col, 32, true); } } } } if (o.PeA < 0) return; if (map.Projection == MapProjection.Polar) return; if (SCANBigMap.eq_frame <= 0) { // predict equatorial crossings for the next 100 loops double TAAN = 360f - o.argumentOfPeriapsis; // true anomaly at ascending node double TADN = (TAAN + 180) % 360; // true anomaly at descending node double MAAN = meanForTrue(TAAN, o.eccentricity); double MADN = meanForTrue(TADN, o.eccentricity); double tAN = (((MAAN - o.meanAnomaly * Mathf.Rad2Deg + 360) % 360) / 360f * o.period + startUT); double tDN = (((MADN - o.meanAnomaly * Mathf.Rad2Deg + 360) % 360) / 360f * o.period + startUT); if (SCANBigMap.eq_an_map == null || SCANBigMap.eq_dn_map == null || SCANBigMap.eq_an_map.Length != maprect.width) { SCANBigMap.eq_an_map = new int[(int)maprect.width]; SCANBigMap.eq_dn_map = new int[(int)maprect.width]; } if (SCANBigMap.eq_map == null || SCANBigMap.eq_map.width != SCANBigMap.eq_an_map.Length) { SCANBigMap.eq_map = new Texture2D(SCANBigMap.eq_an_map.Length, eqh, TextureFormat.ARGB32, false); } for (int i = 0; i < SCANBigMap.eq_an_map.Length; ++i) { SCANBigMap.eq_an_map[i] = 0; SCANBigMap.eq_dn_map[i] = 0; } for (int i = 0; i < 100; ++i) { double UTAN = tAN + o.period * i; double UTDN = tDN + o.period * i; if (double.IsNaN(UTAN) || double.IsNaN(UTDN)) continue; Vector3d pAN = o.getPositionAtUT(UTAN); Vector3d pDN = o.getPositionAtUT(UTDN); double rotAN = 0, rotDN = 0; if (vessel.mainBody.rotates) { rotAN = ((360 * ((UTAN - startUT) / vessel.mainBody.rotationPeriod)) % 360); rotDN = ((360 * ((UTDN - startUT) / vessel.mainBody.rotationPeriod)) % 360); } double loAN = vessel.mainBody.GetLongitude(pAN) - rotAN; double loDN = vessel.mainBody.GetLongitude(pDN) - rotDN; int lonAN = (int)(((map.projectLongitude(loAN, 0) + 180) % 360) * SCANBigMap.eq_an_map.Length / 360f); int lonDN = (int)(((map.projectLongitude(loDN, 0) + 180) % 360) * SCANBigMap.eq_dn_map.Length / 360f); if (lonAN >= 0 && lonAN < SCANBigMap.eq_an_map.Length) SCANBigMap.eq_an_map[lonAN] += 1; if (lonDN >= 0 && lonDN < SCANBigMap.eq_dn_map.Length) SCANBigMap.eq_dn_map[lonDN] += 1; } Color[] pix = SCANBigMap.eq_map.GetPixels(0, 0, SCANBigMap.eq_an_map.Length, eqh); Color cAN = palette.cb_skyBlue, cDN = palette.cb_orange; for (int y = 0; y < eqh; ++y) { Color lc = palette.clear; for (int x = 0; x < SCANBigMap.eq_an_map.Length; ++x) { Color c = palette.clear; float scale = 0; if (y < eqh / 2) { c = cDN; scale = SCANBigMap.eq_dn_map[x]; } else { c = cAN; scale = SCANBigMap.eq_an_map[x]; } if (scale >= 1) { if (y == 0 || y == eqh - 1) { c = palette.black; } else { if (lc == palette.clear) pix[y * SCANBigMap.eq_an_map.Length + x - 1] = palette.black; scale = Mathf.Clamp(scale - 1, 0, 10) / 10f; c = palette.lerp(c, palette.white, scale); } } else { c = palette.clear; if (lc != palette.clear && lc != palette.black) c = palette.black; } pix[y * SCANBigMap.eq_an_map.Length + x] = c; lc = c; } } SCANBigMap.eq_map.SetPixels(0, 0, SCANBigMap.eq_an_map.Length, eqh, pix); SCANBigMap.eq_map.Apply(); SCANBigMap.eq_frame = 4; } else { SCANBigMap.eq_frame -= 1; } if (SCANBigMap.eq_map != null) { r.x = maprect.x; r.y = maprect.y + maprect.height / 2 + -SCANBigMap.eq_map.height / 2; r.width = SCANBigMap.eq_map.width; r.height = SCANBigMap.eq_map.height; GUI.DrawTexture(r, SCANBigMap.eq_map); } }
internal static Dictionary<int, List<List<Vector2d>>> drawGridLine(Rect maprect, SCANmap map) { var lineDict = new Dictionary<int, List<List<Vector2d>>>(); var whiteLineList = new List<List<Vector2d>>(); var blackLineList = new List<List<Vector2d>>(); switch (map.Projection) { case MapProjection.Rectangular: { for (double lon = -150; lon <= 150; lon += 30) { List<Vector2d> points = new List<Vector2d>(); List<Vector2d> pointsBlack = new List<Vector2d>(); points.Add(new Vector2d((int)(map.MapScale * (lon + 180)), 0)); points.Add(new Vector2d((int)(map.MapScale * (lon + 180)), (int)(map.MapScale * 180))); pointsBlack.Add(new Vector2d(points[0].x + 1, points[0].y)); pointsBlack.Add(new Vector2d(points[1].x + 1, points[1].y)); whiteLineList.Add(points); blackLineList.Add(pointsBlack); } for (double lat = -60; lat <= 60; lat += 30) { List<Vector2d> points = new List<Vector2d>(); List<Vector2d> pointsBlack = new List<Vector2d>(); points.Add(new Vector2d(0, (int)(map.MapScale * (lat + 90)))); points.Add(new Vector2d((int)(map.MapScale * 360), (int)(map.MapScale * (lat + 90)))); pointsBlack.Add(new Vector2d(points[0].x, points[0].y - 1)); pointsBlack.Add(new Vector2d(points[1].x, points[1].y - 1)); whiteLineList.Add(points); blackLineList.Add(pointsBlack); } break; } case MapProjection.KavrayskiyVII: { for (double lon = -150; lon <= 150; lon += 30) { List<Vector2d> points = new List<Vector2d>(); List<Vector2d> pointsBlack = new List<Vector2d>(); int i = 0; for (double lat = -88; lat <= 88; lat += 4) { points.Add(new Vector2d((int)(map.MapScale * (map.projectLongitude(lon, lat) + 180)), (int)(map.MapScale * (map.projectLatitude(lon, lat) + 90)))); pointsBlack.Add(new Vector2d(points[i].x + 1, points[i].y)); i++; } whiteLineList.Add(points); blackLineList.Add(pointsBlack); } for (double lat = -60; lat <= 60; lat += 30) { List<Vector2d> points = new List<Vector2d>(); List<Vector2d> pointsBlack = new List<Vector2d>(); points.Add(new Vector2d((int)(map.MapScale * (map.projectLongitude(-179, lat) + 180)), (int)(map.MapScale * (lat + 90)))); points.Add(new Vector2d((int)(map.MapScale * (map.projectLongitude(179, lat) + 180)), (int)(map.MapScale * (lat + 90)))); pointsBlack.Add(new Vector2d(points[0].x, points[0].y - 1)); pointsBlack.Add(new Vector2d(points[1].x, points[1].y - 1)); whiteLineList.Add(points); blackLineList.Add(pointsBlack); } break; } case MapProjection.Polar: { for (double lon = -180; lon <= 150; lon += 30) { List<Vector2d> pointsS = new List<Vector2d>(); List<Vector2d> pointsBlackS = new List<Vector2d>(); pointsS.Add(new Vector2d((int)(map.MapScale * (map.projectLongitude(lon, -88) + 180)), (int)(map.MapScale * (map.projectLatitude(lon, -88) + 90)))); pointsS.Add(new Vector2d((int)(map.MapScale * (map.projectLongitude(lon, -2) + 180)), (int)(map.MapScale * (map.projectLatitude(lon, -2) + 90)))); whiteLineList.Add(pointsS); List<Vector2d> pointsN = new List<Vector2d>(); List<Vector2d> pointsBlackN = new List<Vector2d>(); pointsN.Add(new Vector2d((int)(map.MapScale * (map.projectLongitude(lon, 2) + 180)), (int)(map.MapScale * (map.projectLatitude (lon, 2) + 90)))); pointsN.Add(new Vector2d((int)(map.MapScale * (map.projectLongitude(lon, 88) + 180)), (int)(map.MapScale * (map.projectLatitude(lon, 88) + 90)))); whiteLineList.Add(pointsN); if (lon == -180 || lon == 0) { pointsBlackS.Add(new Vector2d(pointsS[0].x + 1, pointsS[0].y)); pointsBlackS.Add(new Vector2d(pointsS[1].x + 1, pointsS[1].y)); pointsBlackN.Add(new Vector2d(pointsN[0].x + 1, pointsN[0].y)); pointsBlackN.Add(new Vector2d(pointsN[1].x + 1, pointsN[1].y)); } else if (lon == -90 || lon == 90) { pointsBlackS.Add(new Vector2d(pointsS[0].x, pointsS[0].y - 1)); pointsBlackS.Add(new Vector2d(pointsS[1].x, pointsS[1].y - 1)); pointsBlackN.Add(new Vector2d(pointsN[0].x, pointsN[0].y - 1)); pointsBlackN.Add(new Vector2d(pointsN[1].x, pointsN[1].y - 1)); } else if (lon == -60 || lon == -30 || lon == 120 || lon == 150) { pointsBlackS.Add(new Vector2d(pointsS[0].x - 1, pointsS[0].y - 1)); pointsBlackS.Add(new Vector2d(pointsS[1].x - 1, pointsS[1].y - 1)); pointsBlackN.Add(new Vector2d(pointsN[0].x + 1, pointsN[0].y - 1)); pointsBlackN.Add(new Vector2d(pointsN[1].x + 1, pointsN[1].y - 1)); } else { pointsBlackS.Add(new Vector2d(pointsS[0].x + 1, pointsS[0].y - 1)); pointsBlackS.Add(new Vector2d(pointsS[1].x + 1, pointsS[1].y - 1)); pointsBlackN.Add(new Vector2d(pointsN[0].x - 1, pointsN[0].y - 1)); pointsBlackN.Add(new Vector2d(pointsN[1].x - 1, pointsN[1].y - 1)); } blackLineList.Add(pointsBlackS); blackLineList.Add(pointsBlackN); } for (double lat = -88; lat <= 88; lat += 2) { if (lat != 0) { if (lat % 30 == 0 || lat == -88 || lat == 88) { List<Vector2d> points = new List<Vector2d>(); List<Vector2d> pointsBlack = new List<Vector2d>(); for (double lon = -180; lon <= 180; lon += 4) { points.Add(new Vector2d((int)(map.MapScale * (map.projectLongitude(lon, lat) + 180)), (int)(map.MapScale * (map.projectLatitude(lon, lat) + 90)))); float offset = 0; if (lat == 30) offset = -0.8f; else if (lat == -30) offset = 0.8f; else if (lat == 60) offset = -0.3f; else if (lat == -60) offset = 0.3f; if (lat != -88 && lat != 88) pointsBlack.Add(new Vector2d((int)(map.MapScale * (map.projectLongitude(lon, lat + offset) + 180)), (int)(map.MapScale * (map.projectLatitude(lon, lat + offset) + 90)))); } whiteLineList.Add(points); blackLineList.Add(pointsBlack); } } } break; } } lineDict.Add(0, blackLineList); lineDict.Add(1, whiteLineList); return lineDict; }
private static void drawWaypointLabel(Rect maprect, SCANmap map, SCANwaypoint p, SCANdata data) { double lon = SCANUtil.fixLon(p.Longitude); double lat = SCANUtil.fixLat(p.Latitude); if (map != null) { lat = SCANUtil.fixLat(map.projectLatitude(p.Longitude, p.Latitude)); lon = SCANUtil.fixLon(map.projectLongitude(p.Longitude, p.Latitude)); lat = map.scaleLatitude(lat); lon = map.scaleLongitude(lon); if (lat < 0 || lon < 0 || lat > 180 || lon > 360) return; } lon = lon * maprect.width / 360f; lat = maprect.height - lat * maprect.height / 180f; Rect r = new Rect(maprect.x + (float)lon, maprect.y + (float)lat, 24, 24); r.x -= 12; if (!p.LandingTarget) { r.y -= 24; drawMapIcon(r, SCANskins.SCAN_WaypointIcon, true); } else { r.x += 1; r.y -= 13; drawMapIcon(r, SCANcontroller.controller.mechJebTargetSelection ? SCANskins.SCAN_MechJebIcon : SCANskins.SCAN_TargetIcon, true, SCANcontroller.controller.mechJebTargetSelection ? palette.red : palette.xkcd_PukeGreen, true); } }
//Method to draw anomaly labels on the map private static void drawAnomalyLabel(Rect maprect, SCANmap map, SCANanomaly anomaly) { if (!anomaly.Known) return; double lon = SCANUtil.fixLon(anomaly.Longitude); double lat = SCANUtil.fixLat(anomaly.Latitude); if (map != null) { lat = SCANUtil.fixLat(map.projectLatitude(anomaly.Longitude, anomaly.Latitude)); lon = SCANUtil.fixLon(map.projectLongitude(anomaly.Longitude, anomaly.Latitude)); lat = map.scaleLatitude(lat); lon = map.scaleLongitude(lon); if (lat < 0 || lon < 0 || lat > 180 || lon > 360) return; } lon = lon * maprect.width / 360f; lat = maprect.height - lat * maprect.height / 180f; string txt = SCANcontroller.controller.anomalyMarker + " " + anomaly.Name; if (!anomaly.Detail) txt = SCANcontroller.controller.anomalyMarker + " Anomaly"; Rect r = new Rect(maprect.x + (float)lon, maprect.y + (float)lat, 250f, 25f); drawLabel(r, txt, true, true, true); }
//Method to actually draw vessel labels on the map internal static void drawVesselLabel(Rect maprect, SCANmap map, int num, Vessel vessel) { bool flash = false; double lon = SCANUtil.fixLon(vessel.longitude); double lat = SCANUtil.fixLat(vessel.latitude); if (map != null) { lat = SCANUtil.fixLat(map.projectLatitude(vessel.longitude, vessel.latitude)); lon = SCANUtil.fixLon(map.projectLongitude(vessel.longitude, vessel.latitude)); lat = map.scaleLatitude(lat); lon = map.scaleLongitude(lon); if (lat < 0 || lon < 0 || lat > 180 || lon > 360) return; } lon = lon * maprect.width / 360f; lat = maprect.height - lat * maprect.height / 180f; string txt = num.ToString(); if (num == 0) txt = vessel.vesselName; else if (num < 0) txt = ""; Rect r = new Rect(maprect.x + (float)lon, maprect.y + (float)lat, 250f, 25f); Color col = palette.white; if (SCANcontroller.controller.colours == 1 && vessel != FlightGlobals.ActiveVessel) col = palette.cb_skyBlue; if (vessel == FlightGlobals.ActiveVessel && (int)(Time.realtimeSinceStartup % 2) == 0) { flash = true; col = palette.cb_yellow; } int sz = 16; if (vessel.vesselType == VesselType.Flag) sz = 24; SCANicon.drawOrbitIcon((int)r.x, (int)r.y, SCANicon.orbitIconForVesselType(vessel.vesselType), col, sz, true); if (maprect.width < 360) return; r.x += 12; drawLabel(r, txt, flash, true, true); }
/* UI: This isn't really a UI function, so it doesn't belong here. * This is more of a time-projection mathematical function. */ /* FIXME: possible relocation */ private static bool mapPosAtT(Rect maprect, SCANmap map, ref Rect r, Vessel vessel, Orbit o, double dT, double startUT) { double UT = startUT + dT; if (double.IsNaN(UT)) return false; try { if (double.IsNaN(o.getObtAtUT(UT))) return false; Vector3d pos = o.getPositionAtUT(UT); double rotation = 0; if (vessel.mainBody.rotates) { rotation = (360 * (dT / vessel.mainBody.rotationPeriod)) % 360; } double lo = (vessel.mainBody.GetLongitude(pos) - rotation); double la = (vessel.mainBody.GetLatitude(pos)); double lon = (map.projectLongitude(lo, la) + 180) % 360; double lat = (map.projectLatitude(lo, la) + 90) % 180; lat = map.scaleLatitude(lat); lon = map.scaleLongitude(lon); if (lat < 0 || lon < 0 || lat > 180 || lon > 360) return false; lon = lon * maprect.width / 360f; lat = maprect.height - lat * maprect.height / 180f; r.x = maprect.x + (float)lon; r.y = maprect.y + (float)lat; return true; } catch (Exception) { return false; } }