Пример #1
0
        /// <summary>
        /// Runs a query for the data for a particular indicator/resolution/time,
        /// and generates an SLD to color the geographies correctly based on the values.
        /// </summary>
        /// <param name="indicatorId"></param>
        /// <param name="resolutionType"></param>
        /// <param name="timeId"></param>
        /// <param name="scopeBorough"></param>
        /// <param name="scopeSubborough"></param>
        /// <returns></returns>
        public static string GenerateSld(object indicatorId, NycResolutionType resolutionType,
                                         object timeId, object scopeBorough, object scopeSubborough)
        {
            // First load the indicator metadata, both because we need the info, and because
            // if the query is for data that doesn't exist, we can skip a lot of work.
            NycIndicator indicator = GetIndicator(indicatorId);
            // Don't validate time, since there's no easy way to do it other than querying and seeing
            // if we get anything.

            // Now load the configs that tell us what color to render everything as.
            Config cfg = Config.GetConfig("NYC.SLD");

            // Acceptable values are 0 to 100.  So we need a 101 length array.
            string[] colors = new string[101];
            string   color  = null;
            IDictionary <string, IList <object> > geogIdsByColor = new CheckedDictionary <string, IList <object> >();

            for (int x = 0; x < colors.Length; x++)
            {
                // If the value isn't in the config, use the same as the last value.
                color = cfg.GetParameter(indicator.UseAlternateColors ? "AlternateBreakpoints" : "BreakPoints",
                                         x.ToString(), color);
                // Make sure we have a list created for the geogs that will be this color.
                if ((color != null) && (!geogIdsByColor.ContainsKey(color)))
                {
                    geogIdsByColor[color] = new List <object>();
                }
                colors[x] = color;
            }

            string mapLayerName          = cfg.GetParameter("LayerNames", resolutionType.ToString(), null);
            string layerGeogIdField      = cfg.GetParameter("LayerGeographyIdFields", resolutionType.ToString(), null);
            string layerDisplayNameField = cfg.GetParameter("LayerDisplayNameFields", resolutionType.ToString(), null);

            // This includes any labeling and outlines, default background color, etc.
            StringBuilder sldRules = new StringBuilder(cfg.GetConfigInnerXml("DefaultSLD"));

            // Replace any tokens with the appropriate values for this layer.
            sldRules.Replace("{LayerName}", mapLayerName);
            sldRules.Replace("{LayerGeographyIdField}", layerGeogIdField);
            sldRules.Replace("{LayerDisplayNameField}", layerDisplayNameField);

            // If no map layer is defined (I.E. "City"), or the request is invalid in some way,
            // use just the default SLD.
            if (mapLayerName != null)
            {
                // Now query for all the data.
                DaoCriteria crit = new DaoCriteria();
                crit.Expressions.Add(new EqualExpression("IndicatorId", indicatorId));
                crit.Expressions.Add(new EqualExpression("Resolution", resolutionType));
                crit.Expressions.Add(new EqualExpression("TimeId", timeId));
                DaoCriteria geogCrit = null;
                if (scopeBorough != null)
                {
                    geogCrit = new DaoCriteria();
                    geogCrit.Expressions.Add(new EqualExpression("Borough", scopeBorough));
                    if (scopeSubborough != null)
                    {
                        geogCrit.Expressions.Add(new EqualExpression("SubBorough", scopeSubborough));
                    }
                }
                if (geogCrit != null)
                {
                    // Scope and/or subscope was defined.
                    geogCrit.Expressions.Add(new EqualExpression("Resolution", resolutionType));
                    IList <object> geogIdsInScope = new List <object>();
                    foreach (NycGeography geog in _geogDao.Get(geogCrit))
                    {
                        geogIdsInScope.Add(geog.UID);
                    }
                    crit.Expressions.Add(new PropertyInListExpression("GeographyId", geogIdsInScope));
                }
                IList <NycDatum> data = _dataDao.Get(crit);

                // If there's no data, don't make any SLD rules.
                if ((data != null) && (data.Count > 0))
                {
                    foreach (NycDatum datum in data)
                    {
                        int val;
                        switch (indicator.Breakpoint)
                        {
                        case NycBreakpointType.HistoricalBreakpoint:
                            val = datum.HistoricalBreakpoint;
                            break;

                        case NycBreakpointType.ContemporaryBreakpoint:
                            val = datum.ContemporaryBreakpoint;
                            break;

                        default:
                            throw new ArgumentOutOfRangeException("Indicator " + indicator +
                                                                  " has invalid breakpoint: " + indicator.Breakpoint);
                        }
                        if ((val < 0) || (val > 100))
                        {
                            _log.Warn("'Normalized' value " + datum + " was outside 0-100 range.");
                        }

                        // Figure out, based on the value, which color group it belongs to.
                        string thisColor = colors[val];
                        if (thisColor != null)
                        {
                            // Put it in that group.
                            geogIdsByColor[thisColor].Add(datum.GeographyId);
                        }
                    }

                    // Now append the rules for those color groups.
                    foreach (KeyValuePair <string, IList <object> > kvp in geogIdsByColor)
                    {
                        // Only add rules for colors that actually have values.
                        if (kvp.Value.Count > 0)
                        {
                            sldRules.Append("<Rule>");

                            // The part that says what geography IDs get this color.
                            sldRules.Append("<ogc:Filter>");
                            sldRules.Append("<ogc:Or>");
                            foreach (object geogId in kvp.Value)
                            {
                                sldRules.Append("<ogc:PropertyIsEqualTo>");
                                sldRules.Append("<ogc:PropertyName>").Append(layerGeogIdField).Append(
                                    "</ogc:PropertyName>");
                                sldRules.Append("<ogc:Literal>").Append(geogId).Append("</ogc:Literal>");
                                sldRules.Append("</ogc:PropertyIsEqualTo>");
                            }
                            sldRules.Append("</ogc:Or>");
                            sldRules.Append("</ogc:Filter>");

                            // The part that says what color to fill with.
                            sldRules.Append("<PolygonSymbolizer>");
                            sldRules.Append("<Fill>");
                            sldRules.Append("<CssParameter name=\"fill\">").Append(kvp.Key).Append("</CssParameter>");
                            sldRules.Append("<CssParameter name=\"fill-opacity\">").Append(
                                cfg.GetParameter("Polygons", "Opacity")).Append("</CssParameter>");
                            sldRules.Append("</Fill>");
                            sldRules.Append("</PolygonSymbolizer>");

                            sldRules.Append("</Rule>");
                        }
                    }
                }
            }
            // Now wrap all the rendering rules in the SLD outer tags.
            StringBuilder sld = new StringBuilder();

            sld.Append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n")
            .Append("<StyledLayerDescriptor version=\"1.0.0\"")
            .Append(" xsi:schemaLocation=\"http://www.opengis.net/sld StyledLayerDescriptor.xsd\"")
            .Append(" xmlns=\"http://www.opengis.net/sld\"")
            .Append(" xmlns:ogc=\"http://www.opengis.net/ogc\"")
            .Append(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"")
            .Append(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">")
            .Append("<NamedLayer>")
            .Append("<Name>").Append(mapLayerName).Append("</Name>")
            .Append("<UserStyle>")
            .Append("<FeatureTypeStyle>")
            .Append(sldRules.ToString())
            .Append("</FeatureTypeStyle>")
            .Append("</UserStyle>")
            .Append("</NamedLayer>")
            .Append("</StyledLayerDescriptor>");

            return(sld.ToString());
        }
Пример #2
0
        /// <summary>
        /// Gets all columns (visible to the user anyway) and includes the allowed
        /// values for columns that have entries in the Attribute_Values table.
        /// </summary>
        /// <param name="entityType">Only Properties is supported.</param>
        /// <param name="userRoles">The roles the current user has.
        ///                         Only attributes they can see will be returned.</param>
        /// <returns>All the attribute metadata for the specified columns.</returns>
        public static IList <PdbCategory> GetAttributesForClient(
            PdbEntityType entityType, IEnumerable <SecurityRole> userRoles)
        {
            IDictionary <string, IDictionary <string, IList <PdbAttribute> > > attrsByCatAndSub =
                new CheckedDictionary <string, IDictionary <string, IList <PdbAttribute> > >();
            IDictionary <string, IList <PdbAttribute> > attrsByCat =
                new CheckedDictionary <string, IList <PdbAttribute> >();

            DaoCriteria crit = new DaoCriteria();

            crit.Expressions.Add(new EqualExpression("EntityType", entityType));
            IList <PdbAttribute> attrs = GetAttribRecords(crit, userRoles);

            // Get all the attributes and split 'em up.  Put them either into the single
            // or double-nested dictionary depending on if they have subcategories.
            foreach (PdbAttribute attr in attrs)
            {
                IDictionary <string, IList <PdbAttribute> > catSubCats;
                IList <PdbAttribute> catAttrs;
                if (attrsByCatAndSub.ContainsKey(attr.Category))
                {
                    catSubCats = attrsByCatAndSub[attr.Category];
                    catAttrs   = attrsByCat[attr.Category];
                }
                else
                {
                    catSubCats = new CheckedDictionary <string, IList <PdbAttribute> >();
                    catAttrs   = new List <PdbAttribute>();
                    attrsByCatAndSub[attr.Category] = catSubCats;
                    attrsByCat[attr.Category]       = catAttrs;
                }
                // Now either it has a subcategory, in which case it's filed there, or
                // it doesn't, and it's filed under the category directly.
                if (StringHelper.IsNonBlank(attr.SubCategory))
                {
                    IList <PdbAttribute> subcatList;
                    if (catSubCats.ContainsKey(attr.SubCategory))
                    {
                        subcatList = catSubCats[attr.SubCategory];
                    }
                    else
                    {
                        subcatList = new List <PdbAttribute>();
                        catSubCats[attr.SubCategory] = subcatList;
                    }
                    subcatList.Add(attr);
                }
                else
                {
                    catAttrs.Add(attr);
                }
            }
            // Now they're all split up, create the returnable object types.
            // Remember it is impossible for any of the collections to be empty, since we created
            // them all based on records we had.
            List <PdbCategory> retVal = new List <PdbCategory>();

            foreach (KeyValuePair <string, IDictionary <string, IList <PdbAttribute> > > kvp in attrsByCatAndSub)
            {
                IDictionary <string, IList <PdbAttribute> > subCatLists = kvp.Value;
                List <PdbSubCategory> subCats = new List <PdbSubCategory>();
                PdbAttribute          anAttr  = null;
                foreach (IList <PdbAttribute> subCatList in subCatLists.Values)
                {
                    subCats.Add(new PdbSubCategory(subCatList[0].SubCategory,
                                                   subCatList[0].FilterAttrOrder, SimplifyAndGetValues(subCatList)));
                    // save one indicator for the category info.
                    if (anAttr == null)
                    {
                        anAttr = subCatList[0];
                    }
                }
                if (anAttr == null)
                {
                    // subCatList and attrsByCat can't BOTH be empty or we wouldn't have this category.
                    anAttr = attrsByCat[kvp.Key][0];
                }
                retVal.Add(new PdbCategory(anAttr.Category, anAttr.FilterCatOrder,
                                           SimplifyAndGetValues(attrsByCat[kvp.Key]), subCats));
            }
            retVal.Sort();
            return(retVal);
        }
Пример #3
0
        /// <summary>
        /// Returns metadata about all the indicators available.
        /// </summary>
        /// <returns></returns>
        public static IList <NycIndicatorCategory> GetIndicatorMetadata()
        {
            IDictionary <string, IDictionary <string, IList <NycIndicator> > > groups =
                new CheckedDictionary <string, IDictionary <string, IList <NycIndicator> > >();

            // Get all the indicators and split 'em up.
            foreach (NycIndicator ind in _indicatorDao.Get())
            {
                IDictionary <string, IList <NycIndicator> > catGroup;
                if (groups.ContainsKey(ind.Category))
                {
                    catGroup = groups[ind.Category];
                }
                else
                {
                    catGroup             = new CheckedDictionary <string, IList <NycIndicator> >();
                    groups[ind.Category] = catGroup;
                }
                IList <NycIndicator> subcatList;
                if (catGroup.ContainsKey(ind.SubCategory))
                {
                    subcatList = catGroup[ind.SubCategory];
                }
                else
                {
                    subcatList = new List <NycIndicator>();
                    catGroup[ind.SubCategory] = subcatList;
                }
                subcatList.Add(ind);
            }
            // Now they're all split up, create the returnable object types.
            // Remember it is impossible for any of the collections to be empty, since we created
            // them all based on records we had.
            List <NycIndicatorCategory> retVal = new List <NycIndicatorCategory>();

            foreach (IDictionary <string, IList <NycIndicator> > catGroup in groups.Values)
            {
                List <NycIndicatorSubCategory> subCats = new List <NycIndicatorSubCategory>();
                NycIndicator anIndicator = null;
                foreach (IList <NycIndicator> subcatList in catGroup.Values)
                {
                    subCats.Add(new NycIndicatorSubCategory(subcatList));
                    // save one indicator for the category info.
                    if (anIndicator == null)
                    {
                        anIndicator = subcatList[0];
                    }
                }
                retVal.Add(new NycIndicatorCategory(anIndicator, subCats));
            }
            retVal.Sort();

            // Now populate the available times based on resolutions for each indicator.
            IDictionary <object, IDictionary <int, IDictionary <int, IList <int> > > > resByIndic =
                GetResolutionsByIndicator();

            foreach (NycIndicatorCategory cat in retVal)
            {
                foreach (NycIndicatorSubCategory subCat in cat.SubCats)
                {
                    foreach (ThinNycIndicator indic in subCat.Indicators)
                    {
                        // Protect against bad data.
                        if (resByIndic.ContainsKey(indic.UID))
                        {
                            indic.AvailableYearsByResolution = resByIndic[indic.UID];
                        }
                    }
                }
            }
            return(retVal);
        }
Пример #4
0
 /// <summary>
 /// Updates a data object record using the "table" and a list of column/value pairs.
 /// </summary>
 /// <param name="transaction">Should be null, transactions are not supported.</param>
 /// <param name="mapping">The mapping of the table or other data container we're dealing with.</param>
 /// <param name="crit">All records matching this criteria will be updated per the dictionary of
 ///                    values.</param>
 /// <param name="propValues">A dictionary of column/value pairs for all non-ID columns to be updated.</param>
 /// <returns>The number of records affected.</returns>
 public override int Update(ITransaction transaction, ClassMapping mapping, DaoCriteria crit, IDictionary<string, object> propValues)
 {
     switch (_connDesc.Type)
     {
         case CsvConnectionType.Directory:
         case CsvConnectionType.FileName:
             // These are OK.
             break;
         default:
             throw new LoggingException("Connection does not support updating: " + _connDesc);
     }
     // No way to selectively update text from a text file, so instead we first copy all
     // the rows that don't match the criteria into a new file.
     string existingFile = GetFileName(mapping);
     string newFile = existingFile + ".new";
     DaoCriteria inverseCrit = new DaoCriteria();
     foreach (IExpression expr in crit.Expressions)
     {
         inverseCrit.Expressions.Add(expr.Invert());
     }
     TextWriter newWriter = new StreamWriter(newFile, false);
     int rowsUpdated = 0;
     try
     {
         newWriter.WriteLine(MakeHeaderRow(mapping));
         // Copy the rows that don't match...
         CsvDataReader reader = new CsvDataReader(this, mapping, inverseCrit);
         try
         {
             int numCols = reader.FieldCount;
             while (reader.Read())
             {
                 for (int x = 0; x < numCols; x++)
                 {
                     if (x > 0)
                     {
                         newWriter.Write(",");
                     }
                     newWriter.Write(QuoteValue(reader.GetValue(x)));
                 }
                 newWriter.WriteLine();
             }
         }
         finally
         {
             reader.Close();
         }
         // Copy (modified) the rows that do match...
         reader = new CsvDataReader(this, mapping, crit);
         try
         {
             IDictionary<int, object> replacements = new CheckedDictionary<int, object>();
             foreach (KeyValuePair<string, object> kvp in propValues)
             {
                 replacements[reader.GetColumnIndex(kvp.Key)] = kvp.Value;
             }
             int numCols = reader.FieldCount;
             while (reader.Read())
             {
                 rowsUpdated++;
                 for (int x = 0; x < numCols; x++)
                 {
                     if (x > 0)
                     {
                         newWriter.Write(",");
                     }
                     // Use the updated value if one was provided.
                     object val = replacements.ContainsKey(x)
                                      ? replacements[x] : reader.GetValue(x);
                     newWriter.Write(QuoteValue(val));
                 }
                 newWriter.WriteLine();
             }
         }
         finally
         {
             reader.Close();
         }
     }
     finally
     {
         newWriter.Close();
     }
     // Now move the old file out of the way and replace it with the new one.
     File.Replace(newFile, existingFile, existingFile + ".old", true);
     return rowsUpdated;
 }