Exemple #1
0
    private PiecewiseLinearFunction GetColorScale(ContourQuery contourQuery)
    {
        DataTable colorScale;

        using (AdoDataConnection conn = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
        {
            string query =
                "SELECT " +
                "    ContourColorScalePoint.Value, " +
                "    ContourColorScalePoint.Color " +
                "FROM " +
                "    ContourColorScale JOIN " +
                "    ContourColorScalePoint ON ContourColorScalePoint.ContourColorScaleID = ContourColorScale.ID " +
                "WHERE ContourColorScale.Name = {0} " +
                "ORDER BY ContourColorScalePoint.OrderID";

            colorScale = conn.RetrieveData(query, contourQuery.ColorScaleName);
        }

        double[] colorDomain = colorScale
                               .Select()
                               .Select(row => row.ConvertField <double>("Value"))
                               .ToArray();

        double[] colorRange = colorScale
                              .Select()
                              .Select(row => (double)(uint)row.ConvertField <int>("Color"))
                              .ToArray();

        return(new PiecewiseLinearFunction()
               .SetDomain(colorDomain)
               .SetRange(colorRange));
    }
Exemple #2
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();
            }
        }
    }
Exemple #3
0
    private List <TrendingDataLocation> GetFrameFromDailySummary(ContourQuery contourQuery)
    {
        List <TrendingDataLocation> locations = new List <TrendingDataLocation>();

        using (AdoDataConnection conn = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
            using (DataContext dataContext = new DataContext(conn))
                using (IDbCommand cmd = conn.Connection.CreateCommand())
                {
                    var meters = dataContext.Table <Meter>().QueryRecordsWhere("ID IN (SELECT MeterID FROM MeterAssetGroup WHERE AssetGroupID IN (SELECT AssetGroupID FROM UserAccountAssetGroup WHERE UserAccountID =  (SELECT ID FROM UserAccount WHERE Name = {0})))", contourQuery.UserName);

                    if (!string.IsNullOrEmpty(contourQuery.Meters))
                    {
                        const int byteSize = 8;

                        // Meter selections are stored as a base-64 string without padding, using '-' instead of '+' and '_' instead of '/'
                        string padding         = "A===".Remove(3 - (contourQuery.Meters.Length + 3) % 4);
                        string base64          = contourQuery.Meters.Replace('-', '+').Replace('_', '/') + padding;
                        byte[] meterSelections = Convert.FromBase64String(base64);
                        var    ids             = string.Join("", meterSelections.Select(x => Convert.ToString(x, 2)));


                        // The resulting byte array is a simple set of bitflags ordered by meter ID and packed into the most significant bits.
                        // In order to properly interpret the bytes, we must first order the data by meter ID to determine the location of
                        // each meter's bitflag. Then we can filter out the unwanted data from the original list of meters
                        meters = meters
                                 .OrderBy(meter => meter.ID)
                                 .Where((meter, index) => (meterSelections[index / byteSize] & (0x80 >> (index % byteSize))) > 0)
                                 .ToList();
                    }

                    cmd.Parameters.Add(new SqlParameter("@EventDateFrom", contourQuery.GetStartDate()));
                    cmd.Parameters.Add(new SqlParameter("@EventDateTo", contourQuery.GetEndDate()));
                    cmd.Parameters.Add(new SqlParameter("@colorScaleName", contourQuery.ColorScaleName));
                    cmd.Parameters.Add(new SqlParameter("@meterIds", string.Join(",", meters.Select(x => x.ID))));
                    cmd.CommandText    = "dbo.selectMeterLocationsTrendingData";
                    cmd.CommandType    = CommandType.StoredProcedure;
                    cmd.CommandTimeout = 300;

                    using (IDataReader rdr = cmd.ExecuteReader())
                    {
                        while (rdr.Read())
                        {
                            TrendingDataLocation ourStatus = new TrendingDataLocation();
                            ourStatus.Latitude  = (double)rdr["Latitude"];
                            ourStatus.Longitude = (double)rdr["Longitude"];
                            ourStatus.Name      = (string)rdr["Name"];
                            ourStatus.Average   = (rdr.IsDBNull(rdr.GetOrdinal("Average")) ? (double?)null : (double)rdr["Average"]);
                            ourStatus.Maximum   = (rdr.IsDBNull(rdr.GetOrdinal("Maximum")) ? (double?)null : (double)rdr["Maximum"]);
                            ourStatus.Minimum   = (rdr.IsDBNull(rdr.GetOrdinal("Minimum")) ? (double?)null : (double)rdr["Minimum"]);
                            ourStatus.ID        = (int)rdr["id"];
                            locations.Add(ourStatus);
                        }
                    }
                }


        return(locations);
    }
Exemple #4
0
    private InverseDistanceWeightingFunction GetIDWFunction(ContourQuery contourQuery, List <TrendingDataLocation> locations = null)
    {
        CoordinateReferenceSystem crs       = new EPSG3857();
        List <double>             xList     = new List <double>();
        List <double>             yList     = new List <double>();
        List <double>             valueList = new List <double>();

        if ((object)locations == null)
        {
            locations = GetFrameFromDailySummary(contourQuery);
        }

        locations
        .Select(location =>
        {
            GeoCoordinate Coordinate = new GeoCoordinate(location.Latitude, location.Longitude);

            double?Value =
                (contourQuery.DataType == "Average") ? location.Average :
                (contourQuery.DataType == "Minimum") ? location.Minimum :
                (contourQuery.DataType == "Maximum") ? location.Maximum :
                null;

            return(new { Coordinate, Value });
        })
        .Where(obj => (object)obj.Value != null)
        .ToList()
        .ForEach(obj =>
        {
            xList.Add(obj.Coordinate.Longitude);
            yList.Add(obj.Coordinate.Latitude);
            valueList.Add(obj.Value.GetValueOrDefault());
        });

        if (valueList.Count == 0)
        {
            xList.Add(0.0D);
            yList.Add(0.0D);

            using (AdoDataConnection connection = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
            {
                valueList.Add(connection.ExecuteScalar <double>("SELECT NominalValue FROM ContourColorScale WHERE Name = {0}", contourQuery.ColorScaleName));
            }
        }

        return(new InverseDistanceWeightingFunction()
               .SetXCoordinates(xList.ToArray())
               .SetYCoordinates(yList.ToArray())
               .SetValues(valueList.ToArray())
               .SetDistanceFunction((x1, y1, x2, y2) =>
        {
            GeoCoordinate coordinate1 = new GeoCoordinate(y1, x1);
            GeoCoordinate coordinate2 = new GeoCoordinate(y2, x2);
            return crs.Distance(coordinate1, coordinate2);
        }));
    }
    private List<TrendingDataLocation> GetFrameFromDailySummary(ContourQuery contourQuery)
    {
        List<TrendingDataLocation> locations = new List<TrendingDataLocation>();

        using (AdoDataConnection conn = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
        using (IDbCommand cmd = conn.Connection.CreateCommand())
        {
            cmd.Parameters.Add(new SqlParameter("@EventDateFrom", contourQuery.GetStartDate()));
            cmd.Parameters.Add(new SqlParameter("@EventDateTo", contourQuery.GetEndDate()));
            cmd.Parameters.Add(new SqlParameter("@colorScaleName", contourQuery.ColorScaleName));
            cmd.Parameters.Add(new SqlParameter("@username", contourQuery.UserName));
            cmd.CommandText = "dbo.selectMeterLocationsTrendingData";
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandTimeout = 300;

            using (IDataReader rdr = cmd.ExecuteReader())
            {
                while (rdr.Read())
                {
                    TrendingDataLocation ourStatus = new TrendingDataLocation();
                    ourStatus.Latitude = (double)rdr["Latitude"];
                    ourStatus.Longitude = (double)rdr["Longitude"];
                    ourStatus.name = (string)rdr["Name"];
                    ourStatus.Average = (rdr.IsDBNull(rdr.GetOrdinal("Average")) ? (double?)null : (double)rdr["Average"]);
                    ourStatus.Maximum = (rdr.IsDBNull(rdr.GetOrdinal("Maximum")) ? (double?)null : (double)rdr["Maximum"]);
                    ourStatus.Minimum = (rdr.IsDBNull(rdr.GetOrdinal("Minimum")) ? (double?)null : (double)rdr["Minimum"]);
                    ourStatus.id = (int)rdr["id"];
                    locations.Add(ourStatus);
                }
            }
        }

        if (!string.IsNullOrEmpty(contourQuery.Meters))
        {
            const int byteSize = 8;

            // Meter selections are stored as a base-64 string without padding, using '-' instead of '+' and '_' instead of '/'
            string padding = "A==".Remove(3 - (contourQuery.Meters.Length + 3) % 4);
            string base64 = contourQuery.Meters.Replace('-', '+').Replace('_', '/') + padding;
            byte[] meterSelections = Convert.FromBase64String(base64);

            // The resulting byte array is a simple set of bitflags ordered by meter ID and packed into the most significant bits.
            // In order to properly interpret the bytes, we must first order the data by meter ID to determine the location of
            // each meter's bitflag. Then we can filter out the unwanted data from the original list of meters
            locations = locations
                .OrderBy(location => location.id)
                .Where((location, index) => (meterSelections[index / byteSize] & (0x80 >> (index % byteSize))) > 0)
                .ToList();
        }

        return locations;
    }
    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);

                contourTileData.MinLatitude = locations.Min(location => location.Latitude) - GetLatFromMiles(50.0D);
                contourTileData.MaxLatitude = locations.Max(location => location.Latitude) + GetLatFromMiles(50.0D);
                contourTileData.MinLongitude = locations.Min(location => location.Longitude) - GetLngFromMiles(50.0D, 0.0D);
                contourTileData.MaxLongitude = locations.Max(location => location.Longitude) + GetLngFromMiles(50.0D, 0.0D);

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

                return contourTileData;
            }
            finally
            {
                waitHandle.Set();
            }
        }
    }
    private PiecewiseLinearFunction GetColorScale(ContourQuery contourQuery)
    {
        DataTable colorScale;

        using (AdoDataConnection conn = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
        {
            string query =
                "SELECT " +
                "    ContourColorScalePoint.Value, " +
                "    ContourColorScalePoint.Color " +
                "FROM " +
                "    ContourColorScale JOIN " +
                "    ContourColorScalePoint ON ContourColorScalePoint.ContourColorScaleID = ContourColorScale.ID " +
                "WHERE ContourColorScale.Name = {0} " +
                "ORDER BY ContourColorScalePoint.OrderID";

            colorScale = conn.RetrieveData(query, contourQuery.ColorScaleName);
        }

        double[] colorDomain = colorScale
            .Select()
            .Select(row => row.ConvertField<double>("Value"))
            .ToArray();

        double[] colorRange = colorScale
            .Select()
            .Select(row => (double)(uint)row.ConvertField<int>("Color"))
            .ToArray();

        return new PiecewiseLinearFunction()
            .SetDomain(colorDomain)
            .SetRange(colorRange);
    }
    public ContourInfo getLocationsTrendingData(ContourQuery contourQuery)
    {
        List<TrendingDataLocation> locations = new List<TrendingDataLocation>();
        DataTable colorScale;

        using (AdoDataConnection conn = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
        using (IDbCommand cmd = conn.Connection.CreateCommand())
        {
            cmd.Parameters.Add(new SqlParameter("@EventDateFrom", contourQuery.GetStartDate()));
            cmd.Parameters.Add(new SqlParameter("@EventDateTo", contourQuery.GetEndDate()));
            cmd.Parameters.Add(new SqlParameter("@colorScaleName", contourQuery.ColorScaleName));
            cmd.Parameters.Add(new SqlParameter("@username", contourQuery.UserName));
            cmd.CommandText = "dbo.selectMeterLocationsTrendingData";
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandTimeout = 300;

            using (IDataReader rdr = cmd.ExecuteReader())
            {
                while (rdr.Read())
                {
                    TrendingDataLocation ourStatus = new TrendingDataLocation();
                    ourStatus.Latitude = (double)rdr["Latitude"];
                    ourStatus.Longitude = (double)rdr["Longitude"];
                    ourStatus.name = (string)rdr["Name"];
                    ourStatus.Average = (rdr.IsDBNull(rdr.GetOrdinal("Average")) ? (double?)null : (double)rdr["Average"]);
                    ourStatus.Maximum = (rdr.IsDBNull(rdr.GetOrdinal("Maximum")) ? (double?)null : (double)rdr["Maximum"]);
                    ourStatus.Minimum = (rdr.IsDBNull(rdr.GetOrdinal("Minimum")) ? (double?)null : (double)rdr["Minimum"]);
                    ourStatus.id = (int)rdr["id"];
                    ourStatus.data.Add(ourStatus.Average);
                    ourStatus.data.Add(ourStatus.Maximum);
                    ourStatus.data.Add(ourStatus.Minimum);
                    locations.Add(ourStatus);
                }
            }

            string query =
                "SELECT " +
                "    ContourColorScalePoint.Value, " +
                "    ContourColorScalePoint.Color " +
                "FROM " +
                "    ContourColorScale JOIN " +
                "    ContourColorScalePoint ON ContourColorScalePoint.ContourColorScaleID = ContourColorScale.ID " +
                "WHERE ContourColorScale.Name = {0} " +
                "ORDER BY ContourColorScalePoint.OrderID";

            colorScale = conn.RetrieveData(query, contourQuery.ColorScaleName);
        }

        double[] colorDomain = colorScale
            .Select()
            .Select(row => row.ConvertField<double>("Value"))
            .ToArray();

        double[] colorRange = colorScale
            .Select()
            .Select(row => (double)(uint)row.ConvertField<int>("Color"))
            .ToArray();

        return new ContourInfo()
        {
            Locations = locations,
            ColorDomain = colorDomain,
            ColorRange = colorRange,
        };
    }
    private List<TrendingDataLocation> GetFrameFromDailySummary(ContourQuery contourQuery)
    {
        List<TrendingDataLocation> locations = new List<TrendingDataLocation>();

        using (AdoDataConnection conn = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
        using (IDbCommand cmd = conn.Connection.CreateCommand())
        {
            cmd.Parameters.Add(new SqlParameter("@EventDateFrom", contourQuery.GetStartDate()));
            cmd.Parameters.Add(new SqlParameter("@EventDateTo", contourQuery.GetEndDate()));
            cmd.Parameters.Add(new SqlParameter("@colorScaleName", contourQuery.ColorScaleName));
            cmd.Parameters.Add(new SqlParameter("@username", contourQuery.UserName));
            cmd.CommandText = "dbo.selectMeterLocationsTrendingData";
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandTimeout = 300;

            using (IDataReader rdr = cmd.ExecuteReader())
            {
                while (rdr.Read())
                {
                    TrendingDataLocation ourStatus = new TrendingDataLocation();
                    ourStatus.Latitude = (double)rdr["Latitude"];
                    ourStatus.Longitude = (double)rdr["Longitude"];
                    ourStatus.name = (string)rdr["Name"];
                    ourStatus.Average = (rdr.IsDBNull(rdr.GetOrdinal("Average")) ? (double?)null : (double)rdr["Average"]);
                    ourStatus.Maximum = (rdr.IsDBNull(rdr.GetOrdinal("Maximum")) ? (double?)null : (double)rdr["Maximum"]);
                    ourStatus.Minimum = (rdr.IsDBNull(rdr.GetOrdinal("Minimum")) ? (double?)null : (double)rdr["Minimum"]);
                    ourStatus.id = (int)rdr["id"];
                    locations.Add(ourStatus);
                }
            }
        }

        return locations;
    }
    private InverseDistanceWeightingFunction GetIDWFunction(ContourQuery contourQuery, List<TrendingDataLocation> locations = null)
    {
        CoordinateReferenceSystem crs = new EPSG3857();
        List<double> xList = new List<double>();
        List<double> yList = new List<double>();
        List<double> valueList = new List<double>();

        if ((object)locations == null)
            locations = GetFrameFromDailySummary(contourQuery);

        locations
            .Select(location =>
            {
                GeoCoordinate Coordinate = new GeoCoordinate(location.Latitude, location.Longitude);

                double? Value =
                    (contourQuery.DataType == "Average") ? location.Average :
                    (contourQuery.DataType == "Minimum") ? location.Minimum :
                    (contourQuery.DataType == "Maximum") ? location.Maximum :
                    null;

                return new { Coordinate, Value };
            })
            .Where(obj => (object)obj.Value != null)
            .ToList()
            .ForEach(obj =>
            {
                xList.Add(obj.Coordinate.Longitude);
                yList.Add(obj.Coordinate.Latitude);
                valueList.Add(obj.Value.GetValueOrDefault());
            });

        if (valueList.Count == 0)
        {
            xList.Add(0.0D);
            yList.Add(0.0D);

            using (AdoDataConnection connection = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
            {
                valueList.Add(connection.ExecuteScalar<double>("SELECT NominalValue FROM ContourColorScale WHERE Name = {0}", contourQuery.ColorScaleName));
            }
        }

        return new InverseDistanceWeightingFunction()
            .SetXCoordinates(xList.ToArray())
            .SetYCoordinates(yList.ToArray())
            .SetValues(valueList.ToArray())
            .SetDistanceFunction((x1, y1, x2, y2) =>
            {
                GeoCoordinate coordinate1 = new GeoCoordinate(y1, x1);
                GeoCoordinate coordinate2 = new GeoCoordinate(y2, x2);
                return crs.Distance(coordinate1, coordinate2);
            });
    }
Exemple #11
0
    private List <List <TrendingDataLocation> > GetFramesFromHistorian(ContourQuery contourQuery)
    {
        DataTable idTable;
        string    historianServer;
        string    historianInstance;

        using (AdoDataConnection connection = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
        {
            var meters = (new TableOperations <Meter>(connection)).QueryRecordsWhere("ID IN (SELECT MeterID FROM MeterAssetGroup WHERE AssetGroupID IN (SELECT AssetGroupID FROM UserAccountAssetGroup WHERE UserAccountID =  (SELECT ID FROM UserAccount WHERE Name = {0})))", contourQuery.UserName);

            if (!string.IsNullOrEmpty(contourQuery.Meters))
            {
                const int byteSize = 8;

                // Meter selections are stored as a base-64 string without padding, using '-' instead of '+' and '_' instead of '/'
                string padding         = "A===".Remove(3 - (contourQuery.Meters.Length + 3) % 4);
                string base64          = contourQuery.Meters.Replace('-', '+').Replace('_', '/') + padding;
                byte[] meterSelections = Convert.FromBase64String(base64);
                var    ids             = string.Join("", meterSelections.Select(x => Convert.ToString(x, 2)));


                // The resulting byte array is a simple set of bitflags ordered by meter ID and packed into the most significant bits.
                // In order to properly interpret the bytes, we must first order the data by meter ID to determine the location of
                // each meter's bitflag. Then we can filter out the unwanted data from the original list of meters
                meters = meters
                         .OrderBy(meter => meter.ID)
                         .Where((meter, index) => (meterSelections[index / byteSize] & (0x80 >> (index % byteSize))) > 0)
                         .ToList();
            }


            string query =
                "SELECT " +
                "    Channel.ID AS ChannelID, " +
                "    Meter.ID AS MeterID, " +
                "    Meter.Name AS MeterName, " +
                "    MeterLocation.Latitude, " +
                "    MeterLocation.Longitude, " +
                "    Channel.PerUnitValue " +
                "FROM " +
                "    Meter JOIN " +
                "    MeterLocation ON Meter.MeterLocationID = MeterLocation.ID LEFT OUTER JOIN " +
                "    Channel ON " +
                "        Channel.MeterID = Meter.ID AND " +
                "        Channel.ID IN (SELECT ChannelID FROM ContourChannel WHERE ContourColorScaleName = {1}) " +
                "WHERE Meter.ID IN (" + string.Join(",", meters.Select(x => x.ID)) + ")";

            idTable           = connection.RetrieveData(query, contourQuery.UserName, contourQuery.ColorScaleName);
            historianServer   = connection.ExecuteScalar <string>("SELECT Value FROM Setting WHERE Name = 'Historian.Server'") ?? "127.0.0.1";
            historianInstance = connection.ExecuteScalar <string>("SELECT Value FROM Setting WHERE Name = 'Historian.InstanceName'") ?? "XDA";
        }

        //if (!string.IsNullOrEmpty(contourQuery.Meters))
        //{
        //    const int byteSize = 8;

        //    // Meter selections are stored as a base-64 string without padding, using '-' instead of '+' and '_' instead of '/'
        //    string padding = "A===".Remove(3 - (contourQuery.Meters.Length + 3) % 4);
        //    string base64 = contourQuery.Meters.Replace('-', '+').Replace('_', '/') + padding;
        //    byte[] meterSelections = Convert.FromBase64String(base64);

        //    // The resulting byte array is a simple set of bitflags ordered by meter ID and packed into the most significant bits.
        //    // In order to properly interpret the bytes, we must first group and order the data by meter ID to determine the location
        //    // of each meter's bitflag. Then we can filter out the unwanted data from the original table of IDs
        //    idTable.Select()
        //        .Select((Row, Index) => new { Row, Index })
        //        .GroupBy(obj => obj.Row.ConvertField<int>("MeterID"))
        //        .OrderBy(grouping => grouping.Key)
        //        .Where((grouping, index) => (meterSelections[index / byteSize] & (0x80 >> (index % byteSize))) == 0)
        //        .SelectMany(grouping => grouping)
        //        .OrderByDescending(obj => obj.Index)
        //        .ToList()
        //        .ForEach(obj => idTable.Rows.RemoveAt(obj.Index));
        //}

        List <DataRow> meterRows = idTable
                                   .Select()
                                   .DistinctBy(row => row.ConvertField <int>("MeterID"))
                                   .ToList();

        DateTime startDate = contourQuery.GetStartDate();
        DateTime endDate   = contourQuery.GetEndDate();
        int      stepSize  = contourQuery.StepSize;

        // The frames to be included are those whose timestamps fall
        // within the range which is specified by startDate and
        // endDate. We start by aligning startDate and endDate with
        // the nearest frame timestamps which fall within that range
        int startTimeOffset = (int)Math.Ceiling((startDate - startDate.Date).TotalMinutes / stepSize);

        startDate = startDate.Date.AddMinutes(startTimeOffset * stepSize);

        int endTimeOffset = (int)Math.Floor((endDate - endDate.Date).TotalMinutes / stepSize);

        endDate = endDate.Date.AddMinutes(endTimeOffset * stepSize);

        // Since each frame includes data from all timestamps between
        // the previous frame's timestamp and its own timestamp, we
        // must include one additional frame of data before startDate
        startDate = startDate.AddMinutes(-stepSize);

        int frameCount = (int)((endDate - startDate).TotalMinutes / stepSize);

        List <Dictionary <int, TrendingDataLocation> > frames = Enumerable.Repeat(meterRows, frameCount)
                                                                .Select(rows => rows.Select(row => new TrendingDataLocation()
        {
            ID        = row.ConvertField <int>("MeterID"),
            Name      = row.ConvertField <string>("MeterName"),
            Latitude  = row.ConvertField <double>("Latitude"),
            Longitude = row.ConvertField <double>("Longitude")
        }))
                                                                .Select(locations => locations.ToDictionary(location => location.ID))
                                                                .ToList();

        Dictionary <int, double?> nominalLookup = idTable
                                                  .Select("ChannelID IS NOT NULL")
                                                  .ToDictionary(row => row.ConvertField <int>("ChannelID"), row => row.ConvertField <double?>("PerUnitValue"));

        Dictionary <int, List <TrendingDataLocation> > lookup = idTable
                                                                .Select("ChannelID IS NOT NULL")
                                                                .Select(row =>
        {
            int meterID = row.ConvertField <int>("MeterID");

            return(new
            {
                ChannelID = row.ConvertField <int>("ChannelID"),
                Frames = frames.Select(locationLookup => locationLookup[meterID]).ToList()
            });
        })
                                                                .ToDictionary(obj => obj.ChannelID, obj => obj.Frames);

        using (Historian historian = new Historian(historianServer, historianInstance))
        {
            foreach (openHistorian.XDALink.TrendingDataPoint point in historian.Read(lookup.Keys, startDate, endDate))
            {
                List <TrendingDataLocation> locations = lookup[point.ChannelID];

                // Use ceiling to sort data into the next nearest frame.
                // Subtract 1 because startDate was shifted to include one additional frame of data
                int frameIndex = (int)Math.Ceiling((point.Timestamp - startDate).TotalMinutes / stepSize) - 1;

                if (frameIndex < 0 || frameIndex >= locations.Count)
                {
                    continue;
                }

                TrendingDataLocation frame = locations[frameIndex];

                double nominal = nominalLookup[point.ChannelID] ?? 1.0D;
                double value   = point.Value / nominal;

                switch (point.SeriesID)
                {
                case SeriesID.Minimum:
                    frame.Minimum = Math.Min(value, frame.Minimum ?? value);
                    break;

                case SeriesID.Maximum:
                    frame.Maximum = Math.Max(value, frame.Maximum ?? value);
                    break;

                case SeriesID.Average:
                    frame.Aggregate(value);
                    frame.Average = frame.GetAverage();
                    break;
                }
            }
        }

        return(frames
               .Select(frame => frame.Values.ToList())
               .ToList());
    }
Exemple #12
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);
        }
    }
    private InverseDistanceWeightingFunction GetIDWFunction(ContourQuery contourQuery, List<TrendingDataLocation> locations = null)
    {
        CoordinateReferenceSystem crs = new EPSG3857();
        List<double> xList = new List<double>();
        List<double> yList = new List<double>();
        List<double> valueList = new List<double>();

        if ((object)locations == null)
            locations = GetFrameFromDailySummary(contourQuery);

        locations
            .Select(location =>
            {
                GeoCoordinate Coordinate = new GeoCoordinate(location.Latitude, location.Longitude);

                double? Value =
                    (contourQuery.DataType == "Average") ? location.Average :
                    (contourQuery.DataType == "Minimum") ? location.Minimum :
                    (contourQuery.DataType == "Maximum") ? location.Maximum :
                    null;

                return new { Coordinate, Value };
            })
            .Where(obj => (object)obj.Value != null)
            .ToList()
            .ForEach(obj =>
            {
                xList.Add(obj.Coordinate.Longitude);
                yList.Add(obj.Coordinate.Latitude);
                valueList.Add(obj.Value.GetValueOrDefault());
            });

        return new InverseDistanceWeightingFunction()
            .SetXCoordinates(xList.ToArray())
            .SetYCoordinates(yList.ToArray())
            .SetValues(valueList.ToArray())
            .SetDistanceFunction((x1, y1, x2, y2) =>
            {
                GeoCoordinate coordinate1 = new GeoCoordinate(y1, x1);
                GeoCoordinate coordinate2 = new GeoCoordinate(y2, x2);
                return crs.Distance(coordinate1, coordinate2);
            });
    }
    private List<List<TrendingDataLocation>> GetFramesFromHistorian(ContourQuery contourQuery)
    {
        DataTable idTable;
        string historianServer;
        string historianInstance;

        using (AdoDataConnection connection = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
        {
            string query =
                "SELECT " +
                "    Channel.ID AS ChannelID, " +
                "    Meter.ID AS MeterID, " +
                "    Meter.Name AS MeterName, " +
                "    MeterLocation.Latitude, " +
                "    MeterLocation.Longitude, " +
                "    Channel.PerUnitValue " +
                "FROM " +
                "    Meter JOIN " +
                "    MeterLocation ON Meter.MeterLocationID = MeterLocation.ID LEFT OUTER JOIN " +
                "    Channel ON " +
                "        Channel.MeterID = Meter.ID AND " +
                "        Channel.ID IN (SELECT ChannelID FROM ContourChannel WHERE ContourColorScaleName = {1}) " +
                "WHERE " +
                "    Meter.ID IN (SELECT * FROM authMeters({0}))";

            idTable = connection.RetrieveData(query, contourQuery.UserName, contourQuery.ColorScaleName);
            historianServer = connection.ExecuteScalar<string>("SELECT Value FROM Setting WHERE Name = 'Historian.Server'") ?? "127.0.0.1";
            historianInstance = connection.ExecuteScalar<string>("SELECT Value FROM Setting WHERE Name = 'Historian.Instance'") ?? "XDA";
        }

        List<DataRow> meterRows = idTable
            .Select()
            .DistinctBy(row => row.ConvertField<int>("MeterID"))
            .ToList();

        DateTime startDate = contourQuery.GetStartDate();
        DateTime endDate = contourQuery.GetEndDate();
        int stepSize = contourQuery.StepSize;

        // The frames to be included are those whose timestamps fall
        // within the range which is specified by startDate and
        // endDate. We start by aligning startDate and endDate with
        // the nearest frame timestamps which fall within that range
        int startTimeOffset = (int)Math.Ceiling((startDate - startDate.Date).TotalMinutes / stepSize);
        startDate = startDate.Date.AddMinutes(startTimeOffset * stepSize);

        int endTimeOffset = (int)Math.Floor((endDate - endDate.Date).TotalMinutes / stepSize);
        endDate = endDate.Date.AddMinutes(endTimeOffset * stepSize);

        // Since each frame includes data from all timestamps between
        // the previous frame's timestamp and its own timestamp, we
        // must include one additional frame of data before startDate
        startDate = startDate.AddMinutes(-stepSize);

        int frameCount = (int)((endDate - startDate).TotalMinutes / stepSize);

        List<Dictionary<int, TrendingDataLocation>> frames = Enumerable.Repeat(meterRows, frameCount)
            .Select(rows => rows.Select(row => new TrendingDataLocation()
            {
                id = row.ConvertField<int>("MeterID"),
                name = row.ConvertField<string>("MeterName"),
                Latitude = row.ConvertField<double>("Latitude"),
                Longitude = row.ConvertField<double>("Longitude")
            }))
            .Select(locations => locations.ToDictionary(location => location.id))
            .ToList();

        Dictionary<int, double?> nominalLookup = idTable
            .Select("ChannelID IS NOT NULL")
            .ToDictionary(row => row.ConvertField<int>("ChannelID"), row => row.ConvertField<double?>("PerUnitValue"));

        Dictionary<int, List<TrendingDataLocation>> lookup = idTable
            .Select("ChannelID IS NOT NULL")
            .Select(row =>
            {
                int meterID = row.ConvertField<int>("MeterID");

                return new
                {
                    ChannelID = row.ConvertField<int>("ChannelID"),
                    Frames = frames.Select(locationLookup => locationLookup[meterID]).ToList()
                };
            })
            .ToDictionary(obj => obj.ChannelID, obj => obj.Frames);

        using (Historian historian = new Historian(historianServer, historianInstance))
        {
            foreach (TrendingDataPoint point in historian.Read(lookup.Keys, startDate, endDate))
            {
                List<TrendingDataLocation> locations = lookup[point.ChannelID];

                // Use ceiling to sort data into the next nearest frame.
                // Subtract 1 because startDate was shifted to include one additional frame of data
                int frameIndex = (int)Math.Ceiling((point.Timestamp - startDate).TotalMinutes / stepSize) - 1;

                if (frameIndex < 0 || frameIndex >= locations.Count)
                    continue;

                TrendingDataLocation frame = locations[frameIndex];

                double nominal = nominalLookup[point.ChannelID] ?? 1.0D;
                double value = point.Value / nominal;

                switch (point.SeriesID)
                {
                    case SeriesID.Minimum:
                        frame.Minimum = Math.Min(value, frame.Minimum ?? value);
                        break;

                    case SeriesID.Maximum:
                        frame.Maximum = Math.Max(value, frame.Maximum ?? value);
                        break;

                    case SeriesID.Average:
                        frame.Aggregate(value);
                        frame.Average = frame.GetAverage();
                        break;
                }
            }
        }

        return frames
            .Select(frame => frame.Values.ToList())
            .ToList();
    }
    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 minLat = frames.Min(frame => frame.Min(location => location.Latitude)) - GetLatFromMiles(50.0D);
        double maxLat = frames.Min(frame => frame.Max(location => location.Latitude)) + GetLatFromMiles(50.0D);
        double minLng = frames.Min(frame => frame.Min(location => location.Longitude)) - GetLngFromMiles(50.0D, 0.0D);
        double maxLng = frames.Min(frame => frame.Max(location => location.Longitude)) + GetLngFromMiles(50.0D, 0.0D);

        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()
        };
    }
    private List<List<TrendingDataLocation>> GetFramesFromHistorian(ContourQuery contourQuery)
    {
        DataTable idTable;
        string historianServer;
        string historianInstance;

        using (AdoDataConnection connection = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter)))
        {
            string query =
                "SELECT " +
                "    Channel.ID AS ChannelID, " +
                "    Meter.ID AS MeterID, " +
                "    Meter.Name AS MeterName, " +
                "    MeterLocation.Latitude, " +
                "    MeterLocation.Longitude, " +
                "    Channel.PerUnitValue " +
                "FROM " +
                "    Meter JOIN " +
                "    MeterLocation ON Meter.MeterLocationID = MeterLocation.ID LEFT OUTER JOIN " +
                "    Channel ON " +
                "        Channel.MeterID = Meter.ID AND " +
                "        Channel.ID IN (SELECT ChannelID FROM ContourChannel WHERE ContourColorScaleName = {1}) " +
                "WHERE Meter.ID IN (SELECT * FROM authMeters({0}))";

            idTable = connection.RetrieveData(query, contourQuery.UserName, contourQuery.ColorScaleName);
            historianServer = connection.ExecuteScalar<string>("SELECT Value FROM Setting WHERE Name = 'Historian.Server'") ?? "127.0.0.1";
            historianInstance = connection.ExecuteScalar<string>("SELECT Value FROM Setting WHERE Name = 'Historian.Instance'") ?? "XDA";
        }

        if (!string.IsNullOrEmpty(contourQuery.Meters))
        {
            const int byteSize = 8;

            // Meter selections are stored as a base-64 string without padding, using '-' instead of '+' and '_' instead of '/'
            string padding = "A==".Remove(3 - (contourQuery.Meters.Length + 3) % 4);
            string base64 = contourQuery.Meters.Replace('-', '+').Replace('_', '/') + padding;
            byte[] meterSelections = Convert.FromBase64String(base64);

            // The resulting byte array is a simple set of bitflags ordered by meter ID and packed into the most significant bits.
            // In order to properly interpret the bytes, we must first group and order the data by meter ID to determine the location
            // of each meter's bitflag. Then we can filter out the unwanted data from the original table of IDs
            idTable.Select()
                .Select((Row, Index) => new { Row, Index })
                .GroupBy(obj => obj.Row.ConvertField<int>("MeterID"))
                .OrderBy(grouping => grouping.Key)
                .Where((grouping, index) => (meterSelections[index / byteSize] & (0x80 >> (index % byteSize))) == 0)
                .SelectMany(grouping => grouping)
                .OrderByDescending(obj => obj.Index)
                .ToList()
                .ForEach(obj => idTable.Rows.RemoveAt(obj.Index));
        }

        List<DataRow> meterRows = idTable
            .Select()
            .DistinctBy(row => row.ConvertField<int>("MeterID"))
            .ToList();

        DateTime startDate = contourQuery.GetStartDate();
        DateTime endDate = contourQuery.GetEndDate();
        int stepSize = contourQuery.StepSize;

        // The frames to be included are those whose timestamps fall
        // within the range which is specified by startDate and
        // endDate. We start by aligning startDate and endDate with
        // the nearest frame timestamps which fall within that range
        int startTimeOffset = (int)Math.Ceiling((startDate - startDate.Date).TotalMinutes / stepSize);
        startDate = startDate.Date.AddMinutes(startTimeOffset * stepSize);

        int endTimeOffset = (int)Math.Floor((endDate - endDate.Date).TotalMinutes / stepSize);
        endDate = endDate.Date.AddMinutes(endTimeOffset * stepSize);

        // Since each frame includes data from all timestamps between
        // the previous frame's timestamp and its own timestamp, we
        // must include one additional frame of data before startDate
        startDate = startDate.AddMinutes(-stepSize);

        int frameCount = (int)((endDate - startDate).TotalMinutes / stepSize);

        List<Dictionary<int, TrendingDataLocation>> frames = Enumerable.Repeat(meterRows, frameCount)
            .Select(rows => rows.Select(row => new TrendingDataLocation()
            {
                id = row.ConvertField<int>("MeterID"),
                name = row.ConvertField<string>("MeterName"),
                Latitude = row.ConvertField<double>("Latitude"),
                Longitude = row.ConvertField<double>("Longitude")
            }))
            .Select(locations => locations.ToDictionary(location => location.id))
            .ToList();

        Dictionary<int, double?> nominalLookup = idTable
            .Select("ChannelID IS NOT NULL")
            .ToDictionary(row => row.ConvertField<int>("ChannelID"), row => row.ConvertField<double?>("PerUnitValue"));

        Dictionary<int, List<TrendingDataLocation>> lookup = idTable
            .Select("ChannelID IS NOT NULL")
            .Select(row =>
            {
                int meterID = row.ConvertField<int>("MeterID");

                return new
                {
                    ChannelID = row.ConvertField<int>("ChannelID"),
                    Frames = frames.Select(locationLookup => locationLookup[meterID]).ToList()
                };
            })
            .ToDictionary(obj => obj.ChannelID, obj => obj.Frames);

        using (Historian historian = new Historian(historianServer, historianInstance))
        {
            foreach (TrendingDataPoint point in historian.Read(lookup.Keys, startDate, endDate))
            {
                List<TrendingDataLocation> locations = lookup[point.ChannelID];

                // Use ceiling to sort data into the next nearest frame.
                // Subtract 1 because startDate was shifted to include one additional frame of data
                int frameIndex = (int)Math.Ceiling((point.Timestamp - startDate).TotalMinutes / stepSize) - 1;

                if (frameIndex < 0 || frameIndex >= locations.Count)
                    continue;

                TrendingDataLocation frame = locations[frameIndex];

                double nominal = nominalLookup[point.ChannelID] ?? 1.0D;
                double value = point.Value / nominal;

                switch (point.SeriesID)
                {
                    case SeriesID.Minimum:
                        frame.Minimum = Math.Min(value, frame.Minimum ?? value);
                        break;

                    case SeriesID.Maximum:
                        frame.Maximum = Math.Max(value, frame.Maximum ?? value);
                        break;

                    case SeriesID.Average:
                        frame.Aggregate(value);
                        frame.Average = frame.GetAverage();
                        break;
                }
            }
        }

        return frames
            .Select(frame => frame.Values.ToList())
            .ToList();
    }
Exemple #17
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()
        });
    }
    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"]
        };

        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);
        }
    }
        public IHttpActionResult Post(ContourQuery contourQuery)
        {
            try
            {
                List <TrendingDataLocation> locations = new List <TrendingDataLocation>();
                DataTable colorScale;

                using (AdoDataConnection connection = new AdoDataConnection("dbOpenXDA"))
                {
                    DataTable table = connection.RetrieveData(@"
                        DECLARE @EventDateFrom DATETIME = {0}
                        DECLARE @EventDateTo DATETIME = {1}
                        DECLARE @colorScaleName AS varchar(max) = {2}
                        DECLARE @meterIds AS varchar(max) = {3}
                        DECLARE @startDate DATE = CAST(@EventDateFrom AS DATE)
                        DECLARE @endDate DATE = CAST(@EventDateTo AS DATE)

                        DECLARE @thedatefrom AS DATE
                        DECLARE @thedateto AS DATE

                        SET @thedatefrom = CAST(@EventDateFrom AS DATE)
                        SET @thedateto = CAST(@EventDateTo AS DATE)

                        SELECT
                            Meter.ID,
                            Meter.Name,
                            Data.Minimum AS Minimum,
                            Data.Maximum AS Maximum,
                            Data.Average AS Average,
                            Location.Longitude,
                            Location.Latitude
                        FROM
                            Meter LEFT OUTER JOIN
                            (
                                SELECT
                                    ContourChannel.MeterID AS MID,
                                    MIN(Minimum/COALESCE(ContourChannel.PerUnitValue, 1)) AS Minimum,
                                    MAX(Maximum/COALESCE(ContourChannel.PerUnitValue, 1)) AS Maximum,
                                    AVG(Average/COALESCE(ContourChannel.PerUnitValue, 1)) AS Average
                                FROM
                                    ContourChannel JOIN
                                    DailyTrendingSummary ON  DailyTrendingSummary.ChannelID = ContourChannel.ChannelID
                                WHERE Date >= @thedatefrom AND Date <= @thedateto AND ContourColorScaleName = @colorScaleName
                                GROUP BY ContourChannel.MeterID
                            ) AS Data ON Data.MID = Meter.ID JOIN
                            Location ON Meter.LocationID = Location.ID
                            WHERE Meter.ID IN (SELECT * FROM String_To_Int_Table(@meterIds, ','))
                        ORDER BY Meter.Name

                    ", contourQuery.GetStartDate(), contourQuery.GetEndDate(), contourQuery.ColorScaleName, contourQuery.MeterIds);

                    foreach (DataRow row in table.Rows)
                    {
                        TrendingDataLocation ourStatus = new TrendingDataLocation();
                        ourStatus.Latitude  = (double)row["Latitude"];
                        ourStatus.Longitude = (double)row["Longitude"];
                        ourStatus.Name      = (string)row["Name"];
                        ourStatus.Average   = row.Field <double?>("Average");
                        ourStatus.Maximum   = row.Field <double?>("Maximum");
                        ourStatus.Minimum   = row.Field <double?>("Minimum");
                        ourStatus.ID        = (int)row["id"];
                        ourStatus.Data.Add(ourStatus.Average);
                        ourStatus.Data.Add(ourStatus.Maximum);
                        ourStatus.Data.Add(ourStatus.Minimum);
                        locations.Add(ourStatus);
                    }

                    string query =
                        "SELECT " +
                        "    ContourColorScalePoint.Value, " +
                        "    ContourColorScalePoint.Color " +
                        "FROM " +
                        "    ContourColorScale JOIN " +
                        "    ContourColorScalePoint ON ContourColorScalePoint.ContourColorScaleID = ContourColorScale.ID " +
                        "WHERE ContourColorScale.Name = {0} " +
                        "ORDER BY ContourColorScalePoint.OrderID";

                    colorScale = connection.RetrieveData(query, contourQuery.ColorScaleName);
                }

                double[] colorDomain = colorScale
                                       .Select()
                                       .Select(row => row.ConvertField <double>("Value"))
                                       .ToArray();

                double[] colorRange = colorScale
                                      .Select()
                                      .Select(row => (double)(uint)row.ConvertField <int>("Color"))
                                      .ToArray();

                return(Ok(new ContourInfo()
                {
                    Locations = locations,
                    ColorDomain = colorDomain,
                    ColorRange = colorRange,
                    DateTo = contourQuery.EndDate,
                    DateFrom = contourQuery.StartDate
                }));
            }
            catch (Exception ex)
            {
                return(InternalServerError(ex));
            }
        }