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> /// Sort styles by the minimum index of their rules. /// This sorts a slice of the styles, so it returns a sorted /// array but does not change the input. /// </summary> /// <param name="styles"></param> /// <param name="env"></param> private static void SortStyles(List <CartoStyle> styles, Env env) { if (styles.Count == 0) { return; } for (var i = 0; i < styles.Count; i++) { CartoStyle style = styles[i]; style.Index = int.MaxValue; for (int b = 0; b < style.Count; b++) { NodeList <CartoRule> rules = style[b].Rules; for (var r = 0; r < rules.Count; r++) { CartoRule rule = rules[r]; if (rule.Index < style.Index) { style.Index = rule.Index; } } } } styles.Sort(delegate(CartoStyle a, CartoStyle b) { return(a.Index.CompareTo(b.Index)); }); }
public static List <CartoDefinition> Flatten(this Ruleset ruleset, List <CartoDefinition> result, NodeList <CartoSelector> parents, Env env, Logging.Logger logger) { NodeList <CartoSelector> selectors = GetCartoSelectors(ruleset); NodeList <CartoSelector> selectorsResult = new NodeList <CartoSelector>(); if (selectors.Count == 0) { env.Frames.Concat(ruleset.Rules); } // evaluate zoom variables on this object. EvaluateZooms(selectors, env); for (int i = 0; i < selectors.Count; i++) { CartoSelector child = selectors[i]; if (child.Filters == null) { // TODO: is this internal inconsistency? // This is an invalid filterset. continue; } if (parents.Count > 0) { foreach (CartoSelector parent in parents) { object mergedFilters = parent.Filters.CloneWith(child.Filters, env); //new CartoFilterSet(child.Filters); if (mergedFilters == null) { // Filters could be added, but they didn't change the // filters. This means that we only have to clone when // the zoom levels or the attachment is different too. if (parent.Zoom == (parent.Zoom & child.Zoom) && parent.Attachment == child.Attachment && parent.ElementsEqual(child)) { selectorsResult.Add(parent); continue; } else { mergedFilters = parent.Filters; } } else if (mergedFilters is bool && !(Convert.ToBoolean(mergedFilters))) { // The merged filters are invalid, that means we don't // have to clone. continue; } CartoSelector clone = new CartoSelector(child); clone.Filters = (CartoFilterSet)mergedFilters; clone.Zoom = parent.Zoom & child.Zoom; clone.Elements.Clear(); clone.Elements.AddRange(parent.Elements.Concat(child.Elements)); if (parent.Attachment != null && child.Attachment != null) { clone.Attachment = parent.Attachment + '/' + child.Attachment; } else { clone.Attachment = child.Attachment ?? parent.Attachment; } clone.Conditions = parent.Conditions + child.Conditions; clone.Index = child.Index; selectorsResult.Add(clone); } } else { selectorsResult.Add(child); } } NodeList <CartoRule> rules = new NodeList <CartoRule>(); foreach (dotless.Core.Parser.Infrastructure.Nodes.Node rule in ruleset.Rules) { // Recursively flatten any nested rulesets if (rule is Ruleset) { List <CartoDefinition> defs = Flatten(rule as Ruleset, result, selectorsResult, env, logger); } else if (rule is CartoRule) { rules.Add(rule as CartoRule); } else if (rule as CartoInvalidElement) { CartoInvalidElement cie = rule as CartoInvalidElement; env.Logger.Log(dotless.Core.Loggers.LogLevel.Error, "Rule"); Logging.LogFactory.WriteLogEntry(logger, new ParsingException(cie.Value, cie.Location.FileName, Zone.GetLineNumber(cie.Location))); } } int index = rules.Count > 0 ? rules[0].Index : -1; for (int i = 0; i < selectorsResult.Count; i++) { // For specificity sort, use the position of the first rule to allow // defining attachments that are under current element as a descendant // selector. CartoSelector selector = selectorsResult[i]; if (index >= 0) { selector.Index = index; } // make a copy of the rules array, since the next iteration will change zooms CartoRule[] arrRules = new CartoRule[rules.Count]; for (int j = 0; j < arrRules.Length; j++) { arrRules[j] = (CartoRule)rules[j].Clone(); } result.Add(new CartoDefinition(selector, arrRules)); } return(result); }
private static void CreateSymbolizers(Rule rule, Dictionary <string, Dictionary <string, CartoRule> > symbolizers, Env env, ICartoTranslator cartoTranslator) { // Sort symbolizers by the index of their first property definition List <KeyValuePair <string, int> > symOrder = new List <KeyValuePair <string, int> >(); List <int> indexes = new List <int>(); foreach (string key in symbolizers.Keys) { int minIdx = int.MaxValue; var props = symbolizers[key]; foreach (var prop in props) { int index = props[prop.Key].Index; if (index < minIdx) { minIdx = index; } } symOrder.Add(new KeyValuePair <string, int>(key, minIdx)); } // Get a simple list of the symbolizers, in order symOrder.Sort(delegate(KeyValuePair <string, int> a, KeyValuePair <string, int> b) { return(a.Value.CompareTo(b.Value)); }); foreach (KeyValuePair <string, int> kv in symOrder) { var attributes = symbolizers[kv.Key]; var symbolizer = kv.Key.Split('/')[1]; // Skip the magical * symbolizer which is used for universal properties // which are bubbled up to Style elements intead of Symbolizer elements. if (symbolizer == "*") { continue; } // Check if we have all required properties string[] properties = attributes.Keys.ToArray(); string[] values = new string[properties.Length]; string missingProperty = null; bool succ = cartoTranslator.HasRequiredProperties(symbolizer, properties, ref missingProperty); if (!succ) { NodeLocation loc = attributes[missingProperty].Location; throw new Exception(string.Format("A required property '{0}' is missing. Location: Index = {1} ; Source = {2}", missingProperty, loc.Index, loc.Source)); } int i = 0; foreach (string propName in attributes.Keys) { CartoRule cartoRule = attributes[propName]; values[i] = cartoRule.Value.GetValueAsString(env); i++; } Symbolizer sym = cartoTranslator.ToSymbolizer(symbolizer, properties, values); if (sym != null && sym.Enabled) { rule.Symbolizers.Add(sym); } } }
/// <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()); }
/// <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); }