/// <summary> /// Apply inherited styles from their ancestors to them. /// </summary> /// <param name="definitions"></param> /// <param name="env"></param> /// <returns>an array of arrays is returned, in which each array refers to a specific attachment</returns> private static List <CartoStyle> InheritDefinitions(List <CartoDefinition> definitions, Env env) { // definitions are ordered by specificity, // high (index 0) to low Dictionary <string, CartoStyle> byAttachment = new Dictionary <string, CartoStyle>(); Dictionary <string, SortedDictionary <string, CartoDefinition> > byFilter = new Dictionary <string, SortedDictionary <string, CartoDefinition> >(); List <CartoStyle> result = new List <CartoStyle>(); List <CartoDefinition> current; string attachment; // Evaluate the filters specified by each definition with the given // environment to correctly resolve variable references definitions.ForEach(delegate(CartoDefinition def) { def.Filters.Evaluate(env); }); current = new List <CartoDefinition>(); for (int i = 0; i < definitions.Count; i++) { CartoDefinition defI = definitions[i]; attachment = defI.Attachment; current.Clear(); current.Add(defI); if (!byAttachment.ContainsKey(attachment)) { CartoStyle style = new CartoStyle(); style.Attachment = attachment; byAttachment.Add(attachment, style); byAttachment[attachment].Attachment = attachment; byFilter[attachment] = new SortedDictionary <string, CartoDefinition>(); result.Add(byAttachment[attachment]); } // Iterate over all subsequent rules. for (var j = i + 1; j < definitions.Count; j++) { CartoDefinition defJ = definitions[j]; if (defJ.Attachment == attachment) { // Only inherit rules from the same attachment. current = AddRules(current, defJ, byFilter[attachment], env); } } for (var k = 0; k < current.Count; k++) { byFilter[attachment][current[k].Filters.ToString()] = current[k]; byAttachment[attachment].Add(current[k]); } } return(result); }
private static List <CartoDefinition> AddRules(List <CartoDefinition> current, CartoDefinition definition, SortedDictionary <string, CartoDefinition> byFilter, Env env) { var newFilters = definition.Filters; var newRules = definition.Rules; object updatedFilters; CartoDefinition clone, previous; // The current definition might have been split up into // multiple definitions already. for (var k = 0; k < current.Count; k++) { updatedFilters = current[k].Filters.CloneWith(newFilters, env); if (updatedFilters is CartoFilterSet) { string filtersString = (updatedFilters as CartoFilterSet).ToString(); if (!byFilter.TryGetValue(filtersString, out previous)) { previous = null; } if (previous != null) { // There's already a definition with those exact // filters. Add the current definitions' rules // and stop processing it as the existing rule // has already gone down the inheritance chain. previous.AddRules(newRules); } else { clone = (CartoDefinition)current[k].Clone((CartoFilterSet)updatedFilters, env); // Make sure that we're only maintaining the clone // when we did actually add rules. If not, there's // no need to keep the clone around. if (clone.AddRules(newRules) > 0) { // We inserted an element before this one, so we need // to make sure that in the next loop iteration, we're // not performing the same task for this element again, // hence the k++. byFilter.Add(filtersString, clone); current.Insert(k, clone); k++; } } } else if (updatedFilters == null) { // if updatedFilters is null, then adding the filters doesn't // invalidate or split the selector, so we addRules to the // combined selector // Filters can be added, but they don't change the // filters. This means we don't have to split the // definition. // // this is cloned here because of shared classes, see // sharedclass.mss current[k] = (CartoDefinition)current[k].Clone(env); current[k].AddRules(newRules); } // if updatedFeatures is false, then the filters split the rule, // so they aren't the same inheritance chain } return(current); }
/// <summary> /// Creates rules /// </summary> /// <param name="style"></param> /// <param name="def"></param> /// <param name="env"></param> /// <param name="existingFilters"></param> /// <param name="cartoTranslator"></param> private static void CreateRules(FeatureTypeStyle style, CartoDefinition def, Env env, Dictionary <string, int> existingFilters, ICartoTranslator cartoTranslator) { string filter = def.Filters.ToString(); if (!(existingFilters.ContainsKey(filter))) { existingFilters[filter] = 0x7FFFFF; } int available = 0x7FFFFF; ZoomStruct zooms = new ZoomStruct(); zooms.Available = available; NodeList <CartoRule> rules = def.Rules; for (int i = 0; i < rules.Count; i++) { CartoRule cartoRule = rules[i]; zooms.Rule = cartoRule.Zoom; if ((existingFilters[filter] & zooms.Rule) == 0) { continue; } while (((zooms.Current = zooms.Rule) & available) != 0) { Dictionary <string, Dictionary <string, CartoRule> > symbolizers = CollectSymbolizers(def, zooms, i, env, cartoTranslator); if (symbolizers != null && symbolizers.Count > 0) { if ((existingFilters[filter] & zooms.Current) == 0) { continue; } int zoom = existingFilters[filter] & zooms.Current; int startZoom = -1, endZoom = 0; for (int zi = 0; zi <= 22; zi++) { if ((zoom & (1 << zi)) != 0) { if (startZoom == -1) { startZoom = zi; } endZoom = zi; } } Rule rule = new Rule(); rule.Filter = ConvertUtility.ToFilter(def.Filters, cartoTranslator); rule.Name = cartoRule.Instance; if (startZoom > 0) { rule.MaxScale = ConvertUtility.ToScaleDenominator(startZoom); } if (endZoom > 0) { rule.MinScale = ConvertUtility.ToScaleDenominator(endZoom + 1); } CreateSymbolizers(rule, symbolizers, env, cartoTranslator); existingFilters[filter] &= ~zooms.Current; // Check whether the rule has at least one visible symbolizer if (rule.Symbolizers.Count > 0 && rule.Symbolizers.Any(s => s.Enabled == true)) { style.Rules.Add(rule); } } } } //style.Rules.Sort(new RuleComparer()); }
private static Dictionary <string, Dictionary <string, CartoRule> > CollectSymbolizers(CartoDefinition def, ZoomStruct zooms, int i, Env env, ICartoTranslator cartoTranslator) { Dictionary <string, Dictionary <string, CartoRule> > symbolizers = new Dictionary <string, Dictionary <string, CartoRule> >(); NodeList <CartoRule> rules = def.Rules; for (int j = i; j < rules.Count; j++) { CartoRule child = rules[j]; string symName = cartoTranslator.GetSymbolizerName(child.Name); string key = child.Instance + "/" + symName; if ((zooms.Current & child.Zoom) != 0 && (!(symbolizers.ContainsKey(key)) || (symbolizers[key] != null && !(symbolizers[key].ContainsKey(child.Name))))) { zooms.Current &= child.Zoom; if (!(symbolizers.ContainsKey(key))) { symbolizers[key] = new Dictionary <string, CartoRule>(); } symbolizers[key][child.Name] = child; } } if (symbolizers.Count > 0) { zooms.Rule &= (zooms.Available &= ~zooms.Current); return(symbolizers); } return(null); }
/// <summary> /// Creates <see cref="FeatureTypeStyle"/> object /// </summary> /// <param name="styleName"></param> /// <param name="cartoStyle"></param> /// <param name="env"></param> /// <param name="cartoTranslator"></param> /// <returns></returns> private static FeatureTypeStyle CreateStyle(string styleName, CartoStyle cartoStyle, Env env, ICartoTranslator cartoTranslator) { FeatureTypeStyle style = new FeatureTypeStyle(styleName); style.ProcessFeatureOnce = true; List <CartoDefinition> definitions = cartoStyle.Definitions; Dictionary <string, int> existingFilters = null; List <string> imageFilters = new List <string>(); List <string> imageFiltersBuffer = new List <string>(); int k = 0; for (int i = 0; i < definitions.Count; i++) { CartoDefinition def = definitions[i]; NodeList <CartoRule> rules = def.Rules; for (int j = 0; j < rules.Count; j++) { CartoRule cartoRule = rules[j]; string ruleName = cartoRule.Name; if (ruleName == "image-filters") { string filter = cartoRule.Value.ToString(); if (!imageFilters.Contains(filter)) { style.ImageFiltersOptions.Filters.Add(cartoTranslator.ToImageFilter(filter)); style.ImageFiltersOptions.Enabled = true; imageFilters.Add(filter); } k++; } else if (ruleName == "image-filters-inflate") { bool inflate = Convert.ToBoolean(cartoRule.Value.ToString()); if (inflate) { style.ImageFiltersOptions.Enabled = true; } k++; } else if (ruleName == "direct-image-filters") { string filter = cartoRule.Value.ToString(); if (!imageFiltersBuffer.Contains(filter)) { style.ImageFiltersOptions.BufferFilters.Add(cartoTranslator.ToImageFilter(filter)); style.ImageFiltersOptions.Enabled = true; imageFiltersBuffer.Add(filter); } k++; } else if (ruleName == "comp-op") { style.BlendingOptions.CompositingMode = cartoTranslator.ToCompositingMode(cartoRule.Value.Evaluate(env).ToString()); k++; } else if (ruleName == "opacity") { style.BlendingOptions.Opacity = (float)(cartoRule.Value.Evaluate(env) as Number).Value; k++; } if (ruleName == "filter-mode") { string filterMode = cartoRule.Value.Evaluate(env).ToCSS(env); if (string.Equals(filterMode, "all")) { style.ProcessFeatureOnce = false; } else if (string.Equals(filterMode, "first")) { style.ProcessFeatureOnce = true; } k++; } } if (k < rules.Count) { if (existingFilters == null) { existingFilters = new Dictionary <string, int>(); } CreateRules(style, def, env, existingFilters, cartoTranslator); } } return(style); }