public FramingConstellation(Constellation constellation, ViewportFoV viewport) { this.constellation = constellation; Id = constellation.Id; Name = constellation.Name; var constellationStartDec = constellation.Stars.Select(m => m.Coords.Dec).Min(); var constellationStopDec = constellation.Stars.Select(m => m.Coords.Dec).Max(); if (constellation.GoesOverRaZero) { double stopRA = double.MaxValue; double startRA = 0; foreach (var star in constellation.Stars) { if (star.Coords.RADegrees > 180) { stopRA = Math.Min(stopRA, star.Coords.RADegrees); } else { startRA = Math.Max(startRA, star.Coords.RADegrees); } } if (stopRA == double.MaxValue) { stopRA = 0; } var distance = startRA + 360 - stopRA; var centerRa = stopRA + distance / 2; if (centerRa > 360) { centerRa -= 360; } constellationCenter = new Coordinates(centerRa, constellationStopDec + (constellationStartDec - constellationStopDec) / 2, Epoch.J2000, Coordinates.RAType.Degrees); } else { var constellationStartRA = constellation.Stars.Select(m => m.Coords.RADegrees).Min(); var constellationStopRA = constellation.Stars.Select(m => m.Coords.RADegrees).Max(); constellationCenter = new Coordinates( constellationStopRA + (constellationStartRA - constellationStopRA) / 2, constellationStopDec + (constellationStartDec - constellationStopDec) / 2, Epoch.J2000, Coordinates.RAType.Degrees); } Points = new HashSet <Tuple <Star, Star> >(); Stars = new HashSet <Star>(); foreach (var star in constellation.Stars) { star.Radius = (-3.375f * star.Mag + 23.25f) / (float)(viewport.VFoVDeg / 8f); } }
public void RecalculateTopLeft(ViewportFoV reference) { CenterPoint = coordinates.XYProjection(reference); arcSecWidth = reference.ArcSecWidth; arcSecHeight = reference.ArcSecHeight; TextPosition = new PointF((float)CenterPoint.X, (float)(CenterPoint.Y + RadiusHeight + 5)); }
public void CalculatePoints(ViewportFoV viewport) { this.currentViewport = viewport; DetermineStepSizes(); RAPoints.Clear(); DecPoints.Clear(); var raMin = nfmod(viewport.CalcRAMin - viewport.CalcRAMin % currentRAStep - currentRAStep, 360); var raMax = nfmod(viewport.CalcRAMax - viewport.CalcRAMax % currentRAStep + currentRAStep, 360); if (viewport.HFoVDeg == 360) { raMin = 0; raMax = 360 - currentRAStep; } if (raMin > raMax) { for (double ra = 0; ra <= raMax; ra += currentRAStep) { CalculateRAPoints(ra); } for (double ra = raMin; ra < 360; ra += currentRAStep) { CalculateRAPoints(ra); } } else { for (double ra = raMin; ra <= raMax; ra += currentRAStep) { CalculateRAPoints(ra); } } var currentMinDec = Math.Max(-MAXDEC, Math.Min(viewport.CalcTopDec, viewport.CalcBottomDec)); var currentMaxDec = Math.Min(MAXDEC, Math.Max(viewport.CalcTopDec, viewport.CalcBottomDec)); if (currentMaxDec > 0) { var start = Math.Max(0, Math.Max(0, currentMinDec) % currentDecStep - currentDecStep); for (double dec = start; dec <= currentMaxDec; dec += currentDecStep) { CalculateDecPoints(dec); } } if (currentMinDec < 0) { var start = Math.Min(0, Math.Min(0, currentMinDec) % currentDecStep + currentDecStep); for (double dec = start; dec >= currentMinDec; dec -= currentDecStep) { CalculateDecPoints(dec); } } }
public void CalculatePoints(ViewportFoV viewport) { // calculate the lines based on fov height and current dec to avoid projection issues // atan gnomoric projection cannot project properly over 90deg, it will result in the same results as prior // and dec lines will overlap each other var(raStep, decStep, raStart, raStop, decStart, decStop) = CalculateStepsAndStartStopValues(viewport); var pointsByDecDict = new Dictionary <double, FrameLine>(); // if raStep is 30 and decStep is 1 just bool raIsClosed = RoundToHigherValue(viewport.AbsCalcTopDec, decStep) >= MAXDEC; for (double ra = Math.Min(raStart, raStop); ra <= Math.Max(raStop, raStart); ra += raStep) { List <PointF> raPointCollection = new List <PointF>(); for (double dec = Math.Min(decStart, decStop); dec <= Math.Max(decStart, decStop); dec += decStep) { var point = new Coordinates(ra, dec, Epoch.J2000, Coordinates.RAType.Degrees).XYProjection(viewport); var pointf = new PointF((float)point.X, (float)point.Y); if (!pointsByDecDict.ContainsKey(dec)) { pointsByDecDict.Add(dec, new FrameLine() { Closed = raIsClosed, Collection = new List <PointF> { pointf }, StrokeThickness = dec == 0 ? 3 : 1 }); } else { pointsByDecDict[dec].Collection.Add(pointf); } raPointCollection.Add(pointf); } // those are the vertical lines RAPoints.Add(new FrameLine { StrokeThickness = (ra == 0 || ra == 180) ? 3 : 1, Closed = false, Collection = raPointCollection }); } // those are actually the circles foreach (KeyValuePair <double, FrameLine> item in pointsByDecDict) { DecPoints.Add(item.Value); } }
public ViewportFoV ChangeFoV(double vFoVDegrees) { ConstellationsInViewport.Clear(); ClearFrameLineMatrix(); ViewportFoV = new ViewportFoV(ViewportFoV.CenterCoordinates, vFoVDegrees, ViewportFoV.OriginalWidth, ViewportFoV.OriginalHeight, ViewportFoV.Rotation); FrameLineMatrix.CalculatePoints(ViewportFoV); UpdateSkyMap(); return(ViewportFoV); }
/// <summary> /// Constructor for a Framing DSO. /// It takes a ViewportFoV and a DeepSkyObject and calculates XY values in pixels from the top left edge of the image subtracting half of its size. /// Those coordinates can be used to place the DSO including its name and size in any given image. /// </summary> /// <param name="dso">The DSO including its coordinates</param> /// <param name="viewport">The viewport of the offending DSO</param> public FramingDSO(DeepSkyObject dso, ViewportFoV viewport) { dsoType = dso.DSOType; arcSecWidth = viewport.ArcSecWidth; arcSecHeight = viewport.ArcSecHeight; if (dso.Size != null && dso.Size >= arcSecWidth) { sizeWidth = dso.Size.Value; } else { sizeWidth = DSO_DEFAULT_SIZE; } if (dso.Size != null && dso.Size >= arcSecHeight) { sizeHeight = dso.Size.Value; } else { sizeHeight = DSO_DEFAULT_SIZE; } Id = dso.Id; Name1 = dso.Name; Name2 = dso.AlsoKnownAs.FirstOrDefault(m => m.StartsWith("M ")); Name3 = dso.AlsoKnownAs.FirstOrDefault(m => m.StartsWith("NGC ")); if (Name3 != null && Name1 == Name3.Replace(" ", "")) { Name1 = null; } if (Name1 == null && Name2 == null) { Name1 = Name3; Name3 = null; } if (Name1 == null && Name2 != null) { Name1 = Name2; Name2 = Name3; Name3 = null; } coordinates = dso.Coordinates; RecalculateTopLeft(viewport); }
public void RecalculateConstellationPoints(ViewportFoV reference, bool calculateConnections) { // calculate all star positions for the constellation once and add them to the star collection for drawing if they're visible foreach (var star in constellation.Stars) { var starPosition = star.Coords.XYProjection(reference); star.Position = new PointF((float)starPosition.X, (float)starPosition.Y); var isInBounds = !reference.IsOutOfViewportBounds(star.Position); var contains = Stars.Contains(star); if (isInBounds && !contains) { Stars.Add(star); } else if (!isInBounds && contains) { Stars.Remove(star); } } if (calculateConnections) { // now we check what lines are visible in the fov and only add those connections as well foreach (var starConnection in constellation.StarConnections) { var isInBounds = !(reference.IsOutOfViewportBounds(starConnection.Item1.Position) && reference.IsOutOfViewportBounds(starConnection.Item2.Position)); var contains = Points.Contains(starConnection); if (isInBounds && !contains) { Points.Add(starConnection); } else if (!isInBounds && contains) { Points.Remove(starConnection); } } var p = constellationCenter.XYProjection(reference); CenterPoint = new PointF((float)p.X, (float)p.Y); } }
public async Task Initialize(Coordinates centerCoordinates, double vFoVDegrees, double imageWidth, double imageHeight, double imageRotation, CancellationToken ct) { telescopeMediator.RemoveConsumer(this); AnnotateDSO = true; AnnotateGrid = true; ViewportFoV = new ViewportFoV(centerCoordinates, vFoVDegrees, imageWidth, imageHeight, imageRotation); if (dbConstellations == null) { dbConstellations = await dbInstance.GetConstellationsWithStars(ct); } if (dbDSOs == null) { dbDSOs = (await dbInstance.GetDeepSkyObjects(string.Empty, new DatabaseInteraction.DeepSkyObjectSearchParams(), ct)).ToDictionary(x => x.Id, y => y); } ConstellationsInViewport.Clear(); ClearFrameLineMatrix(); img = new Bitmap((int)ViewportFoV.OriginalWidth, (int)ViewportFoV.OriginalHeight, PixelFormat.Format32bppArgb); g = Graphics.FromImage(img); g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit; g.SmoothingMode = SmoothingMode.AntiAlias; FrameLineMatrix.CalculatePoints(ViewportFoV); if (ConstellationBoundaries.Count == 0) { ConstellationBoundaries = await GetConstellationBoundaries(); } telescopeMediator.RegisterConsumer(this); Initialized = true; UpdateSkyMap(); }
private (double raStep, double decStep, double raStart, double raStop, double decStart, double decStop) CalculateStepsAndStartStopValues(ViewportFoV viewport) { double raStart; double raStop; double decStart; double decStop; double raStep; double decStep; var realTopDec = viewport.AbsCalcTopDec; var realBottomDec = viewport.AbsCalcBottomDec; if (realTopDec >= MAXDEC) { realTopDec = MAXDEC; raStep = 30; // 12 lines at top decStep = 1; raStart = 0; raStop = 360 - raStep; } else { // we want at least 4 lines // get the steps that are closest to vFovDegTotal and closest to hFovDeg decStep = viewport.VFoVDeg / 4; decStep = DECSTEPS.Aggregate((x, y) => Math.Abs(x - decStep) < Math.Abs(y - decStep) ? x : y); raStep = viewport.HFoVDeg / 4; raStep = RASTEPS.Aggregate((x, y) => Math.Abs(x - raStep) < Math.Abs(y - raStep) ? x : y); // avoid "crash" using a higher fov and getting close to dec, so it doesn't move from e.g. 16 to 1 instantly but "smoothly" if (realTopDec + decStep > MAXDEC) { do { if (decStep == 1) { realTopDec = MAXDEC; raStep = 30; break; } decStep = DECSTEPS[Array.FindIndex(DECSTEPS, w => w == decStep) - 1]; } while (realTopDec + decStep > MAXDEC); } if (raStep != 30) { // round properly so all ra lines are always visible and not cut off unless raStep is 30 raStop = viewport.TopLeft.RADegrees - viewport.HFoVDeg < 0 ? RoundToHigherValue(viewport.TopLeft.RADegrees - viewport.HFoVDeg, raStep) : RoundToLowerValue(viewport.TopLeft.RADegrees - viewport.HFoVDeg, raStep); raStart = RoundToHigherValue(viewport.TopLeft.RADegrees, raStep); } else { raStart = 0; raStop = 360 - raStep; } } // if the top declination point is at max declination we have to round the lower declination point up so it doesn't get cut off if (realTopDec == MAXDEC) { decStart = RoundToHigherValue(realBottomDec, decStep); } else { // otherwise round according to the location of the dec to avoid cutting off decStart = realBottomDec < 0 ? RoundToHigherValue(realBottomDec, decStep) : RoundToLowerValue(realBottomDec, decStep); } // we want to round decstop always higher decStop = RoundToHigherValue(realTopDec, decStep); if (decStop >= MAXDEC) { decStop = MAXDEC; } // flip coordinates if necessary decStart *= viewport.AboveZero ? 1 : -1; decStop *= viewport.AboveZero ? 1 : -1; return(raStep, decStep, raStart, raStop, decStart, decStop); }