예제 #1
0
    private ContourTileData GetContourTileData(ContourQuery contourQuery)
    {
        string          key             = new ConnectionStringParser().ComposeConnectionString(contourQuery);
        ContourTileData contourTileData = new ContourTileData();
        CacheItemPolicy cacheItemPolicy = new CacheItemPolicy()
        {
            SlidingExpiration = TimeSpan.FromMinutes(1)
        };

        contourTileData = (ContourTileData)s_contourDataCache.AddOrGetExisting(key, contourTileData, cacheItemPolicy) ?? contourTileData;

        if ((object)contourTileData.IDWFunction != null && (object)contourTileData.ColorFunction != null)
        {
            return(contourTileData);
        }

        using (ManualResetEvent waitHandle = new ManualResetEvent(false))
        {
            ManualResetEvent cachedWaitHandle = Interlocked.CompareExchange(ref contourTileData.WaitHandle, waitHandle, null);

            try
            {
                try
                {
                    if ((object)cachedWaitHandle != null)
                    {
                        cachedWaitHandle.WaitOne();
                        return(contourTileData);
                    }
                }
                catch (ObjectDisposedException)
                {
                    return(contourTileData);
                }

                List <TrendingDataLocation> locations     = GetFrameFromDailySummary(contourQuery);
                Func <double, double>       colorFunction = GetColorScale(contourQuery);
                IDWFunc idwFunction = GetIDWFunction(contourQuery, locations);

                if (locations.Any())
                {
                    double latDif = locations.Max(location => location.Latitude) - locations.Min(location => location.Latitude);
                    double lonDif = locations.Max(location => location.Longitude) - locations.Min(location => location.Longitude);
                    contourTileData.MinLatitude  = locations.Min(location => location.Latitude) - (latDif * 0.1D);
                    contourTileData.MaxLatitude  = locations.Max(location => location.Latitude) + (latDif * 0.1D);
                    contourTileData.MinLongitude = locations.Min(location => location.Longitude) - (lonDif * 0.1D);
                    contourTileData.MaxLongitude = locations.Max(location => location.Longitude) + (lonDif * 0.1D);
                }

                contourTileData.IDWFunction   = idwFunction;
                contourTileData.ColorFunction = colorFunction;

                return(contourTileData);
            }
            finally
            {
                waitHandle.Set();
            }
        }
    }
        private IDWFunc GetConverter()
        {
            DistanceFunc distanceFunction = m_distanceFunction;

            double[] xCoordinates = m_xCoordinates ?? new double[0];
            double[] yCoordinates = m_yCoordinates ?? new double[0];
            double[] values       = m_values ?? new double[0];
            double   power        = m_power;

            if (xCoordinates.Length != yCoordinates.Length)
            {
                throw new InvalidOperationException($"The number of x-coordinates must match the number of y-coordinates. ({xCoordinates.Length} != {yCoordinates.Length})");
            }

            if (xCoordinates.Length != values.Length)
            {
                throw new InvalidOperationException($"The number of coordinates must match the number of values. ({xCoordinates.Length} != {values.Length})");
            }

            if (xCoordinates.Length == 0)
            {
                return((x, y) => 0.0D);
            }

            return(m_converter ?? (m_converter = (x, y) =>
            {
                double numerator = 0.0D;
                double denominator = 0.0D;

                for (int i = 0; i < xCoordinates.Length; i++)
                {
                    double distance = distanceFunction(x, y, xCoordinates[i], yCoordinates[i]);

                    if (distance == 0.0D)
                    {
                        return values[i];
                    }

                    double inverseDistance = Math.Pow(1.0D / distance, power);
                    numerator += values[i] * inverseDistance;
                    denominator += inverseDistance;
                }

                return numerator / denominator;
            }));
        }
 /// <summary>
 /// Sets the function to be used to calculate the distance between two points.
 /// </summary>
 /// <param name="distanceFunction">The function used to calculate distance between two points.</param>
 /// <returns>A reference to the inverse distance weighting function.</returns>
 public InverseDistanceWeightingFunction SetDistanceFunction(DistanceFunc distanceFunction)
 {
     m_converter        = null;
     m_distanceFunction = distanceFunction ?? DefaultDistanceFunction;
     return(this);
 }
 /// <summary>
 /// Sets the power applied to the inverse distance to control the speed of value's decay.
 /// </summary>
 /// <param name="power">The power applied to the inverse of the distance.</param>
 /// <returns>A reference to the inverse distance weighting function.</returns>
 /// <remarks>Larger values increase the speed of decay such that a known value affects a smaller area.</remarks>
 public InverseDistanceWeightingFunction SetPower(double power)
 {
     m_converter = null;
     m_power     = power;
     return(this);
 }
 /// <summary>
 /// Sets the collection of values of points at which the values are known.
 /// </summary>
 /// <param name="values">The values of points at which the values are known.</param>
 /// <returns>A reference to the inverse distance weighting function.</returns>
 public InverseDistanceWeightingFunction SetValues(params double[] values)
 {
     m_converter = null;
     m_values    = values;
     return(this);
 }
 /// <summary>
 /// Sets the collection of y-coordinates of points at which the values are known.
 /// </summary>
 /// <param name="yCoordinates">The y-coordinates of points at which the values are known.</param>
 /// <returns>A reference to the inverse distance weighting function.</returns>
 public InverseDistanceWeightingFunction SetYCoordinates(params double[] yCoordinates)
 {
     m_converter    = null;
     m_yCoordinates = yCoordinates;
     return(this);
 }
예제 #7
0
    public void getContourTile()
    {
        ContourQuery contourQuery = new ContourQuery()
        {
            StartDate      = HttpContext.Current.Request.QueryString["StartDate"],
            EndDate        = HttpContext.Current.Request.QueryString["EndDate"],
            ColorScaleName = HttpContext.Current.Request.QueryString["ColorScaleName"],
            DataType       = HttpContext.Current.Request.QueryString["DataType"],
            UserName       = HttpContext.Current.Request.QueryString["Username"],
            Meters         = HttpContext.Current.Request.QueryString["Meters"],
            MeterIds       = HttpContext.Current.Request.QueryString["MeterIds"]
        };

        ContourTileData contourTileData = GetContourTileData(contourQuery);

        double minLat = contourTileData.MinLatitude;
        double maxLat = contourTileData.MaxLatitude;
        double minLng = contourTileData.MinLongitude;
        double maxLng = contourTileData.MaxLongitude;

        CoordinateReferenceSystem crs       = s_crs;
        IDWFunc idwFunction                 = contourTileData.IDWFunction;
        Func <double, double> colorFunction = contourTileData.ColorFunction;

        int tileX = Convert.ToInt32(HttpContext.Current.Request.QueryString["x"]);
        int tileY = Convert.ToInt32(HttpContext.Current.Request.QueryString["y"]);
        int zoom  = Convert.ToInt32(HttpContext.Current.Request.QueryString["zoom"]);

        int tileSize = 256;
        int offsetX  = tileSize * tileX;
        int offsetY  = tileSize * tileY;

        uint[] pixelData = new uint[tileSize * tileSize];

        for (int x = 0; x < tileSize; x++)
        {
            GSF.Drawing.Point validationPixel      = new GSF.Drawing.Point(offsetX + x, 0.0D);
            GeoCoordinate     validationCoordinate = crs.Translate(validationPixel, zoom);

            if (validationCoordinate.Longitude < minLng || validationCoordinate.Longitude > maxLng)
            {
                continue;
            }

            for (int y = 0; y < tileSize; y++)
            {
                GSF.Drawing.Point offsetPixel     = new GSF.Drawing.Point(offsetX + x, offsetY + y);
                GeoCoordinate     pixelCoordinate = crs.Translate(offsetPixel, zoom);

                if (pixelCoordinate.Latitude < minLat || pixelCoordinate.Latitude > maxLat)
                {
                    continue;
                }

                double interpolatedValue = idwFunction(pixelCoordinate.Longitude, pixelCoordinate.Latitude);
                uint   color             = (uint)colorFunction(interpolatedValue);
                pixelData[y * tileSize + x] = color;
            }
        }

        using (Bitmap bitmap = BitmapExtensions.FromPixelData(256, pixelData))
        {
            HttpContext.Current.Response.ContentType = "image/png";
            HttpContext.Current.Response.AddHeader("Content-Disposition", string.Format("attachment;filename=tile{0}x{1}.png", tileX, tileY));
            bitmap.Save(HttpContext.Current.Response.OutputStream, ImageFormat.Png);
        }
    }
예제 #8
0
    public ContourAnimationInfo getContourAnimations(ContourQuery contourQuery)
    {
        List <List <TrendingDataLocation> > frames     = GetFramesFromHistorian(contourQuery);
        PiecewiseLinearFunction             colorScale = GetColorScale(contourQuery);
        Func <double, double> colorFunc = colorScale;

        // The actual startDate is the timestamp of the
        // first frame after contourQuery.GetStartDate()
        DateTime startDate       = contourQuery.GetStartDate();
        int      stepSize        = contourQuery.StepSize;
        int      startTimeOffset = (int)Math.Ceiling((startDate - startDate.Date).TotalMinutes / stepSize);

        startDate = startDate.Date.AddMinutes(startTimeOffset * stepSize);
        double latDif = frames.Min(frame => frame.Max(location => location.Latitude)) - frames.Min(frame => frame.Min(location => location.Latitude));
        double lonDif = frames.Min(frame => frame.Max(location => location.Longitude)) - frames.Min(frame => frame.Min(location => location.Longitude));

        double minLat = frames.Min(frame => frame.Min(location => location.Latitude)) - (latDif * 0.1D);
        double maxLat = frames.Min(frame => frame.Max(location => location.Latitude)) + (latDif * 0.1D);
        double minLng = frames.Min(frame => frame.Min(location => location.Longitude)) - (lonDif * 0.1D);
        double maxLng = frames.Min(frame => frame.Max(location => location.Longitude)) + (lonDif * 0.1D);

        GeoCoordinate topLeft     = new GeoCoordinate(maxLat, minLng);
        GeoCoordinate bottomRight = new GeoCoordinate(minLat, maxLng);

        GSF.Drawing.Point topLeftPoint     = s_crs.Translate(topLeft, contourQuery.Resolution);
        GSF.Drawing.Point bottomRightPoint = s_crs.Translate(bottomRight, contourQuery.Resolution);

        topLeftPoint     = new GSF.Drawing.Point(Math.Floor(topLeftPoint.X), Math.Floor(topLeftPoint.Y));
        bottomRightPoint = new GSF.Drawing.Point(Math.Ceiling(bottomRightPoint.X), Math.Ceiling(bottomRightPoint.Y));
        topLeft          = s_crs.Translate(topLeftPoint, contourQuery.Resolution);
        bottomRight      = s_crs.Translate(bottomRightPoint, contourQuery.Resolution);

        int width  = (int)(bottomRightPoint.X - topLeftPoint.X + 1);
        int height = (int)(bottomRightPoint.Y - topLeftPoint.Y + 1);

        int    animationID;
        string timeZoneID = null;

        using (AdoDataConnection connection = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
        {
            connection.ExecuteNonQuery("INSERT INTO ContourAnimation(ColorScaleName, StartTime, EndTime, StepSize) VALUES({0}, {1}, {2}, {3})", contourQuery.ColorScaleName, contourQuery.GetStartDate(), contourQuery.GetEndDate(), contourQuery.StepSize);
            animationID = connection.ExecuteScalar <int>("SELECT @@IDENTITY");

            if (contourQuery.IncludeWeather)
            {
                timeZoneID = connection.ExecuteScalar <string>("SELECT Value FROM Setting WHERE Name = 'XDATimeZone'");
            }
        }

        GSF.Threading.CancellationToken cancellationToken = new GSF.Threading.CancellationToken();
        s_cancellationTokens[animationID] = cancellationToken;

        ProgressCounter progressCounter = new ProgressCounter(frames.Count);

        s_progressCounters[animationID] = progressCounter;

        Action <int> createFrame = i =>
        {
            List <TrendingDataLocation> frame = frames[i];
            IDWFunc idwFunction = GetIDWFunction(contourQuery, frame);
            uint[]  pixelData;

            if (contourQuery.IncludeWeather)
            {
                TimeZoneInfo tzInfo = !string.IsNullOrEmpty(timeZoneID)
                    ? TimeZoneInfo.FindSystemTimeZoneById(timeZoneID)
                    : TimeZoneInfo.Local;

                // Weather data is only available in 5-minute increments
                DateTime frameTime      = TimeZoneInfo.ConvertTimeToUtc(startDate.AddMinutes(stepSize * i), tzInfo);
                double   minutes        = (frameTime - frameTime.Date).TotalMinutes;
                int      weatherMinutes = (int)Math.Ceiling(minutes / 5) * 5;

                NameValueCollection queryString = HttpUtility.ParseQueryString(string.Empty);
                queryString["service"]     = "WMS";
                queryString["request"]     = "GetMap";
                queryString["layers"]      = "nexrad-n0r-wmst";
                queryString["format"]      = "image/png";
                queryString["transparent"] = "true";
                queryString["version"]     = "1.1.1";
                queryString["time"]        = frameTime.Date.AddMinutes(weatherMinutes).ToString("o");
                queryString["height"]      = height.ToString();
                queryString["width"]       = width.ToString();
                queryString["srs"]         = "EPSG:3857";

                GSF.Drawing.Point topLeftProjected     = s_crs.Projection.Project(topLeft);
                GSF.Drawing.Point bottomRightProjected = s_crs.Projection.Project(bottomRight);
                queryString["bbox"] = string.Join(",", topLeftProjected.X, bottomRightProjected.Y, bottomRightProjected.X, topLeftProjected.Y);

                string weatherURL = "http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r-t.cgi?" + queryString.ToString();

                using (WebClient client = new WebClient())
                    using (MemoryStream stream = new MemoryStream(client.DownloadData(weatherURL)))
                        using (Bitmap bitmap = new Bitmap(stream))
                        {
                            pixelData = bitmap.ToPixelData();
                        }
            }
            else
            {
                pixelData = new uint[width * height];
            }

            if (cancellationToken.IsCancelled)
            {
                return;
            }

            for (int x = 0; x < width; x++)
            {
                if (cancellationToken.IsCancelled)
                {
                    return;
                }

                for (int y = 0; y < height; y++)
                {
                    if (cancellationToken.IsCancelled)
                    {
                        return;
                    }

                    if (pixelData[y * width + x] > 0)
                    {
                        continue;
                    }

                    GSF.Drawing.Point offsetPixel       = new GSF.Drawing.Point(topLeftPoint.X + x, topLeftPoint.Y + y);
                    GeoCoordinate     pixelCoordinate   = s_crs.Translate(offsetPixel, contourQuery.Resolution);
                    double            interpolatedValue = idwFunction(pixelCoordinate.Longitude, pixelCoordinate.Latitude);
                    pixelData[y * width + x] = (uint)colorFunc(interpolatedValue);
                }
            }

            if (cancellationToken.IsCancelled)
            {
                return;
            }

            using (Bitmap bitmap = BitmapExtensions.FromPixelData(width, pixelData))
                using (MemoryStream stream = new MemoryStream())
                {
                    bitmap.Save(stream, ImageFormat.Png);

                    using (AdoDataConnection connection = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
                    {
                        connection.ExecuteNonQuery("INSERT INTO ContourAnimationFrame VALUES({0}, {1}, {2})", animationID, i, stream.ToArray());
                    }
                }

            progressCounter.Increment();
        };

        Task.Run(() =>
        {
            ICancellationToken token;
            ProgressCounter counter;
            Parallel.For(0, frames.Count, createFrame);
            s_cancellationTokens.TryRemove(animationID, out token);
            s_progressCounters.TryRemove(animationID, out counter);

            if (cancellationToken.IsCancelled)
            {
                using (AdoDataConnection connection = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
                {
                    connection.ExecuteNonQuery("DELETE FROM ContourAnimationFrame WHERE ContourAnimationID = {0}", animationID);
                    connection.ExecuteNonQuery("DELETE FROM ContourAnimation WHERE ID = {0}", animationID);
                }
            }
        });

        s_cleanUpAnimationOperation.TryRunOnceAsync();

        return(new ContourAnimationInfo()
        {
            AnimationID = animationID,
            ColorDomain = colorScale.Domain,
            ColorRange = colorScale.Range,
            MinLatitude = bottomRight.Latitude,
            MaxLatitude = topLeft.Latitude,
            MinLongitude = topLeft.Longitude,
            MaxLongitude = bottomRight.Longitude,
            Infos = frames.Select((frame, index) => new ContourInfo()
            {
                Locations = frame,
                URL = string.Format("./mapService.asmx/getContourAnimationFrame?animation={0}&frame={1}", animationID, index),
                Date = contourQuery.GetStartDate().AddMinutes(index * contourQuery.StepSize).ToString()
            }).ToList()
        });
    }
예제 #9
0
        private IDWFunc GetConverter()
        {
            DistanceFunc distanceFunction = m_distanceFunction;
            double[] xCoordinates = m_xCoordinates ?? new double[0];
            double[] yCoordinates = m_yCoordinates ?? new double[0];
            double[] values = m_values ?? new double[0];
            double power = m_power;

            if (xCoordinates.Length != yCoordinates.Length)
                throw new InvalidOperationException($"The number of x-coordinates must match the number of y-coordinates. ({xCoordinates.Length} != {yCoordinates.Length})");

            if (xCoordinates.Length != values.Length)
                throw new InvalidOperationException($"The number of coordinates must match the number of values. ({xCoordinates.Length} != {values.Length})");

            if (xCoordinates.Length == 0)
                return (x, y) => 0.0D;

            return m_converter ?? (m_converter = (x, y) =>
            {
                double numerator = 0.0D;
                double denominator = 0.0D;

                for (int i = 0; i < xCoordinates.Length; i++)
                {
                    double distance = distanceFunction(x, y, xCoordinates[i], yCoordinates[i]);

                    if (distance == 0.0D)
                        return values[i];

                    double inverseDistance = Math.Pow(1.0D / distance, power);
                    numerator += values[i] * inverseDistance;
                    denominator += inverseDistance;
                }

                return numerator / denominator;
            });
        }
예제 #10
0
 /// <summary>
 /// Sets the function to be used to calculate the distance between two points.
 /// </summary>
 /// <param name="distanceFunction">The function used to calculate distance between two points.</param>
 /// <returns>A reference to the inverse distance weighting function.</returns>
 public InverseDistanceWeightingFunction SetDistanceFunction(DistanceFunc distanceFunction)
 {
     m_converter = null;
     m_distanceFunction = distanceFunction ?? DefaultDistanceFunction;
     return this;
 }
예제 #11
0
 /// <summary>
 /// Sets the power applied to the inverse distance to control the speed of value's decay.
 /// </summary>
 /// <param name="power">The power applied to the inverse of the distance.</param>
 /// <returns>A reference to the inverse distance weighting function.</returns>
 /// <remarks>Larger values increase the speed of decay such that a known value affects a smaller area.</remarks>
 public InverseDistanceWeightingFunction SetPower(double power)
 {
     m_converter = null;
     m_power = power;
     return this;
 }
예제 #12
0
 /// <summary>
 /// Sets the collection of values of points at which the values are known.
 /// </summary>
 /// <param name="values">The values of points at which the values are known.</param>
 /// <returns>A reference to the inverse distance weighting function.</returns>
 public InverseDistanceWeightingFunction SetValues(params double[] values)
 {
     m_converter = null;
     m_values = values;
     return this;
 }
예제 #13
0
 /// <summary>
 /// Sets the collection of y-coordinates of points at which the values are known.
 /// </summary>
 /// <param name="yCoordinates">The y-coordinates of points at which the values are known.</param>
 /// <returns>A reference to the inverse distance weighting function.</returns>
 public InverseDistanceWeightingFunction SetYCoordinates(params double[] yCoordinates)
 {
     m_converter = null;
     m_yCoordinates = yCoordinates;
     return this;
 }