internal static ISystem GetSystemNearestTo(Point3D currentpos,
                                                   Point3D wantedpos,
                                                   double maxfromcurpos,
                                                   double maxfromwanted,
                                                   SystemsNearestMetric routemethod,
                                                   SQLiteConnectionSystem cn,
                                                   Action <ISystem> LookedUp = null,
                                                   int limitto = 1000)
        {
            using (DbCommand cmd = cn.CreateSelect("Systems s",
                                                   MakeSystemQueryNamed,
                                                   where :
                                                   "x >= @xc - @maxfromcurpos " +
                                                   "AND x <= @xc + @maxfromcurpos " +
                                                   "AND z >= @zc - @maxfromcurpos " +
                                                   "AND z <= @zc + @maxfromcurpos " +
                                                   "AND x >= @xw - @maxfromwanted " +
                                                   "AND x <= @xw + @maxfromwanted " +
                                                   "AND z >= @zw - @maxfromwanted " +
                                                   "AND z <= @zw + @maxfromwanted " +
                                                   "AND y >= @yc - @maxfromcurpos " +
                                                   "AND y <= @yc + @maxfromcurpos " +
                                                   "AND y >= @yw - @maxfromwanted " +
                                                   "AND y <= @yw + @maxfromwanted ",
                                                   orderby: "(s.x-@xw)*(s.x-@xw)+(s.y-@yw)*(s.y-@yw)+(s.z-@zw)*(s.z-@zw)", // orderby distance from wanted
                                                   limit: limitto,
                                                   joinlist: MakeSystemQueryNamedJoinList))
            {
                cmd.AddParameterWithValue("@xw", SystemClass.DoubleToInt(wantedpos.X));         // easier to manage with named paras
                cmd.AddParameterWithValue("@yw", SystemClass.DoubleToInt(wantedpos.Y));
                cmd.AddParameterWithValue("@zw", SystemClass.DoubleToInt(wantedpos.Z));
                cmd.AddParameterWithValue("@maxfromwanted", SystemClass.DoubleToInt(maxfromwanted));
                cmd.AddParameterWithValue("@xc", SystemClass.DoubleToInt(currentpos.X));
                cmd.AddParameterWithValue("@yc", SystemClass.DoubleToInt(currentpos.Y));
                cmd.AddParameterWithValue("@zc", SystemClass.DoubleToInt(currentpos.Z));
                cmd.AddParameterWithValue("@maxfromcurpos", SystemClass.DoubleToInt(maxfromcurpos));

                //System.Diagnostics.Debug.WriteLine(cn.ExplainQueryPlanString(cmd));

                using (DbDataReader reader = cmd.ExecuteReader())
                {
                    var systems = MakeSystemEnumerable(reader, callback: LookedUp);

                    return(GetSystemNearestTo(systems, currentpos, wantedpos, maxfromcurpos, maxfromwanted, routemethod));
                }
            }
        }
        internal static ISystem GetSystemNearestTo(IEnumerable <ISystem> systems,            // non database helper function
                                                   Point3D currentpos,
                                                   Point3D wantedpos,
                                                   double maxfromcurpos,
                                                   double maxfromwanted,
                                                   SystemsNearestMetric routemethod)
        {
            double  bestmindistance = double.MaxValue;
            ISystem nearestsystem   = null;

            foreach (var s in systems)
            {
                Point3D syspos = new Point3D(s.X, s.Y, s.Z);
                double  distancefromwantedx2 = Point3D.DistanceBetweenX2(wantedpos, syspos);  // range between the wanted point and this, ^2
                double  distancefromcurposx2 = Point3D.DistanceBetweenX2(currentpos, syspos); // range between the wanted point and this, ^2

                // ENSURE its withing the circles now
                if (distancefromcurposx2 <= (maxfromcurpos * maxfromcurpos) && distancefromwantedx2 <= (maxfromwanted * maxfromwanted))
                {
                    if (routemethod == SystemsNearestMetric.IterativeNearestWaypoint)
                    {
                        if (distancefromwantedx2 < bestmindistance)
                        {
                            nearestsystem   = s;
                            bestmindistance = distancefromwantedx2;
                        }
                    }
                    else
                    {
                        Point3D interceptpoint = currentpos.InterceptPoint(wantedpos, syspos);      // work out where the perp. intercept point is..
                        double  deviation      = Point3D.DistanceBetween(interceptpoint, syspos);
                        double  metric         = 1E39;

                        if (routemethod == SystemsNearestMetric.IterativeMinDevFromPath)
                        {
                            metric = deviation;
                        }
                        else if (routemethod == SystemsNearestMetric.IterativeMaximumDev100Ly)
                        {
                            metric = (deviation <= 100) ? distancefromwantedx2 : metric;        // no need to sqrt it..
                        }
                        else if (routemethod == SystemsNearestMetric.IterativeMaximumDev250Ly)
                        {
                            metric = (deviation <= 250) ? distancefromwantedx2 : metric;
                        }
                        else if (routemethod == SystemsNearestMetric.IterativeMaximumDev500Ly)
                        {
                            metric = (deviation <= 500) ? distancefromwantedx2 : metric;
                        }
                        else if (routemethod == SystemsNearestMetric.IterativeWaypointDevHalf)
                        {
                            metric = Math.Sqrt(distancefromwantedx2) + deviation / 2;
                        }
                        else
                        {
                            throw new ArgumentOutOfRangeException(nameof(routemethod));
                        }

                        if (metric < bestmindistance)
                        {
                            nearestsystem   = s;
                            bestmindistance = metric;
                        }
                    }
                }
            }

            return(nearestsystem);
        }