private void addTitleStyleElement(TitleStyle TitleStyle, XmlDocument doc, XmlElement layerElement) { XmlElement titleStyleElement = doc.CreateElement("title_style"); layerElement.AppendChild(titleStyleElement); addAttribute(doc, titleStyleElement, "visible", TitleStyle.TitlesVisible ? "1" : "0"); addAttribute(doc, titleStyleElement, "visible_scale", TitleStyle.VisibleScale.ToString(CultureInfo.InvariantCulture)); addAttribute(doc, titleStyleElement, "color", ColorTranslator.ToHtml(TitleStyle.Color)); addAttribute(doc, titleStyleElement, "font_name", TitleStyle.FontFamily); addAttribute(doc, titleStyleElement, "font_size", TitleStyle.FontSize.ToString(CultureInfo.InvariantCulture)); addAttribute(doc, titleStyleElement, "font_style", ((int)TitleStyle.FontStyle).ToString(CultureInfo.InvariantCulture)); addAttribute(doc, titleStyleElement, "render_priority", ((int)TitleStyle.RenderPriority).ToString(CultureInfo.InvariantCulture)); addAttribute(doc, titleStyleElement, "use_outline", TitleStyle.UseOutline ? "1" : "0"); addAttribute(doc, titleStyleElement, "outline_size", TitleStyle.OutlineSize.ToString(CultureInfo.InvariantCulture)); addAttribute(doc, titleStyleElement, "lead_along", TitleStyle.LeadAlong ? "1" : "0"); }
/// <summary> /// Draw a polygon. /// </summary> protected virtual void DrawPolygon(Feature feature, Graphics g, PolygonStyle style, TitleStyle titleStyle, BoundingRectangle viewBox, bool titleVisible, double scaleFactor) { if (feature.Polygon.Contours.Count == 0) return; //if (feature.Layer != null && feature.Layer.Title == "adp.TAB") //{ // drawPrismPolygon(feature, g, viewBox, scaleFactor); // // inscription // if (!string.IsNullOrEmpty(feature.Title) && titleVisible) // addTitleBufferElement(g, feature, titleStyle, viewBox, scaleFactor); // return; //} if (!_isSelectionRendering && feature.Selected) { PolygonBufferElement element = new PolygonBufferElement(feature, style, titleStyle, titleVisible); _selectedPolygons.Add(element); return; } double pixelsize = 1/scaleFactor; if (_reduceSubpixelDetails) { if (feature.BoundingRectangle.Width < pixelsize && feature.BoundingRectangle.Height < pixelsize) return; Polygon tempPolygon = (Polygon) feature.Polygon.Clone(); tempPolygon.Weed(pixelsize); Feature tempFeature = new Feature(FeatureType.Polygon); tempFeature.Title = feature.Title; tempFeature.Selected = feature.Selected; tempFeature.Polygon = tempPolygon; feature = tempFeature; if (feature.Polygon.Contours.Count == 0) return; } using (Pen pen = style.GetPen()) { using (GraphicsPath path = new GraphicsPath(FillMode.Alternate)) { path.StartFigure(); float x = (float) ((feature.Polygon.Contours[0].Vertices[0].X - viewBox.MinX)*scaleFactor); float y = (float) ((viewBox.MaxY - feature.Polygon.Contours[0].Vertices[0].Y)*scaleFactor); g.RenderingOrigin = new Point((int) Math.Round(x), (int) Math.Round(y)); foreach (Contour c in feature.Polygon.Contours) { // there is no point in trying to draw the contours of the degenerate if (c.Vertices.Count <= 2) continue; PointF[] points = new PointF[c.Vertices.Count]; for (int j = 0; j < c.Vertices.Count; j++) { points[j].X = (float) ((c.Vertices[j].X - viewBox.MinX)*scaleFactor); points[j].Y = (float) ((viewBox.MaxY - c.Vertices[j].Y)*scaleFactor); } if (points.Length > 2) path.AddPolygon(points); } path.CloseFigure(); // Fill polygon using (Brush b = style.GetBrush()) { if (style.FillPatternInternal != null) { int w = style.FillPatternInternal.Width; int h = style.FillPatternInternal.Height; ((TextureBrush) b).TranslateTransform(g.RenderingOrigin.X%w, g.RenderingOrigin.Y%h); } g.FillPath(b, path); } if (feature.Selected) { //Fills the selected polygon //Color color = Color.FromArgb(50, _selectionColor); //using (Brush b = new HatchBrush(HatchStyle.Percent70, color, Color.Transparent)) if (_selectionColorChanged || _selectionTexture == null) createSelectionTexture(); using (Brush b = new TextureBrush(_selectionTexture)) { ((TextureBrush) b).TranslateTransform(g.RenderingOrigin.X%8, g.RenderingOrigin.Y%8); g.FillPath(b, path); } // boundary of the selected polygons using (Pen p = new Pen(_selectionColor, style.BorderWidth + 3)) { p.LineJoin = LineJoin.Bevel; g.DrawPath(p, path); } } //boundary of the landfill if (style.BorderVisible) g.DrawPath(pen, path); } // inscription if (!string.IsNullOrEmpty(feature.Title) && titleVisible) addTitleBufferElement(g, feature, titleStyle, viewBox, scaleFactor); } }
/// <summary> /// Drawing the line. /// </summary> protected virtual void DrawPolyline(Feature feature, Graphics g, PolylineStyle style, TitleStyle titleStyle, BoundingRectangle viewBox, bool titleVisible, double scaleFactor) { if (!_isSelectionRendering && feature.Selected) { PolylineBufferElement element = new PolylineBufferElement(feature, style, titleStyle, titleVisible); _selectedPolylines.Add(element); return; } double pixelsize = 1/scaleFactor; if (_reduceSubpixelDetails) { if (feature.BoundingRectangle.Width < pixelsize && feature.BoundingRectangle.Height < pixelsize) return; Polyline p1 = (Polyline) feature.Polyline.Clone(); p1.Weed(pixelsize); Feature tempFeature = new Feature(FeatureType.Polyline); tempFeature.Title = feature.Title; tempFeature.Selected = feature.Selected; tempFeature.Polyline = p1; feature = tempFeature; if (feature.Polyline.Paths.Count == 0) return; } using (Pen pen = style.GetPen()) { if (Math.Min(viewBox.Width/(feature.BoundingRectangle.Width), viewBox.Height/(feature.BoundingRectangle.Height)) < 2) drawPolylineWithIntersectCalculation(g, feature, style, viewBox, scaleFactor); else drawPolylineSimple(g, feature, style, viewBox, scaleFactor); // inscription if (!string.IsNullOrEmpty(feature.Title) && titleVisible) addTitleBufferElement(g, feature, titleStyle, viewBox, scaleFactor); } }
/// <summary> /// Draw a point. /// </summary> protected virtual void DrawPoint(Feature feature, Graphics g, PointStyle style, TitleStyle titleStyle, BoundingRectangle viewBox, bool titleVisible, double scaleFactor) { if (!_isSelectionRendering && feature.Selected) { PointBufferElement element = new PointBufferElement(feature, style, titleStyle, titleVisible); _selectedPoints.Add(element); return; } string _fontName = string.IsNullOrEmpty(style.FontName) ? _symbolsDefaultFontName : style.FontName; using (Font f = new Font(_fontName, style.Size, FontStyle.Regular, GraphicsUnit.Pixel)) { using (SolidBrush fontBrush = new SolidBrush(style.Color)) { SizeF size; SizeF offset; if (style.DisplayKind == PointDisplayKind.Symbol) // character size size = g.MeasureString(style.Symbol.ToString(), f, new PointF(0, 0), _symbolStringFormat); else { // image size if (style.Image != null) size = new SizeF(style.Image.Width, style.Image.Height); else size = new SizeF(1, 1); } //Offset relative to the center point offset = new SizeF(size.Width/2,size.Height/2); switch (style.ContentAlignment) { case ContentAlignment.TopLeft: offset = new SizeF(0, 0); break; case ContentAlignment.TopCenter: offset = new SizeF(size.Width / 2,0); break; case ContentAlignment.TopRight: offset = new SizeF(size.Width, 0); break; case ContentAlignment.BottomLeft: offset = new SizeF(0, size.Height ); break; case ContentAlignment.BottomCenter: offset = new SizeF(size.Width / 2, size.Height); break; case ContentAlignment.BottomRight: offset = new SizeF(size.Width, size.Height); break; case ContentAlignment.MiddleLeft: offset = new SizeF(0, size.Height / 2); break; case ContentAlignment.MiddleCenter: offset = new SizeF(size.Width / 2, size.Height / 2); break; case ContentAlignment.MiddleRight: offset = new SizeF(size.Width, size.Height / 2); break; default: throw new NotSupportedException(); } IEnumerable<ICoordinate> targetPoints = null; if (feature.FeatureType == FeatureType.Point) targetPoints = new ICoordinate[] {feature.Point.Coordinate}; else targetPoints = feature.MultiPoint.Points; foreach (ICoordinate targetPoint in targetPoints) { if (style.DisplayKind == PointDisplayKind.Symbol) { // symbol using (GraphicsPath path = new GraphicsPath()) { path.AddString(style.Symbol.ToString(), f.FontFamily, (int) f.Style, f.Size, new PointF((float) ((targetPoint.X - viewBox.MinX)*scaleFactor-offset.Width), (float) ((viewBox.MaxY - targetPoint.Y)*scaleFactor -offset.Height)), _symbolStringFormat); g.FillPath(fontBrush, path); } } else { // image if (style.Image != null) g.DrawImageUnscaled(style.Image, new Point( (int) Math.Round(((targetPoint.X - viewBox.MinX)*scaleFactor - offset.Width)), (int) Math.Round(((viewBox.MaxY - targetPoint.Y)*scaleFactor - offset.Height)))); } if (feature.Selected) { // Frame selected object using (Pen p = new Pen(_selectionColor, 2)) g.DrawRectangle(p, (float)((targetPoint.X - viewBox.MinX) * scaleFactor - offset.Width + 1), (float)((viewBox.MaxY - targetPoint.Y) * scaleFactor - offset.Height + 1), size.Width - 2, size.Height - 2); using (Brush b = new SolidBrush(Color.FromArgb(50, _selectionColor))) g.FillRectangle(b, (float)((targetPoint.X - viewBox.MinX) * scaleFactor - offset.Width), (float)((viewBox.MaxY - targetPoint.Y) * scaleFactor - offset.Height), size.Width, size.Height); } } // inscription if (!string.IsNullOrEmpty(feature.Title) && titleVisible) { if (feature.FeatureType == FeatureType.Point) { //Location signs point object can not be determined only by coordinates, //without knowing the size of the image of a point object. //Therefore, the ordinate of a point object is displaced by half the size of the symbol. Feature shp = new Feature(FeatureType.Point); shp.Point = new PointD(feature.Point.X, feature.Point.Y + size.Height/2/scaleFactor); shp.Title = feature.Title; addTitleBufferElement(g, shp, titleStyle, viewBox, scaleFactor); } if (feature.FeatureType == FeatureType.MultiPoint) addTitleBufferElement(g, feature, titleStyle, viewBox, scaleFactor); } } } }
void IFeatureRenderer.DrawPolygon(Feature feature, Graphics g, PolygonStyle style, TitleStyle titleStyle, BoundingRectangle viewBox, bool titleVisible, double scaleFactor) { DrawPolygon(feature, g, style, titleStyle, viewBox, titleVisible, scaleFactor); }
public PointBufferElement(Feature point, PointStyle style, TitleStyle titleStyle, bool titleVisible) { _style = style; _titleStyle = titleStyle; _point = point; _titleVisible = titleVisible; }
public PolylineBufferElement(Feature polyline, PolylineStyle style, TitleStyle titleStyle, bool titleVisible) { _style = style; _titleStyle = titleStyle; _polyline = polyline; _titleVisible = titleVisible; }
public PolygonBufferElement(Feature polygon, PolygonStyle style, TitleStyle titleStyle, bool titleVisible) { _style = style; _titleStyle = titleStyle; _polygon = polygon; _titleVisible = titleVisible; }
/// <summary> /// Creates a copy of an inscription TitleBufferElement located along the object. /// </summary> public TitleBufferElement(FollowingTitle followingTitle, TitleStyle style, int number) { _isSimple = false; _style = style; _box = new Segment(followingTitle.GetBoundingBox().Min, followingTitle.GetBoundingBox().Max); _followingTitle = followingTitle; _titleCount = number; }
/// <summary> /// Creates an instance of the appropriate TitleBufferElement simple inscription. /// </summary> public TitleBufferElement(TitleStyle style, Segment box, string title, int number) { _style = style; _title = title; _box = box; _titleCount = number; }
private FollowingTitle getFollowingTitle(Graphics g, LinePath part, double length, string label, TitleStyle titleStyle, BoundingRectangle viewBox, double scaleFactor) { StringFormat format = StringFormat.GenericTypographic; SizeF sizeF; PointF zeroPoint = new PointF(0, 0); using (Font f = titleStyle.GetFont()) { sizeF = g.MeasureString(label, f, zeroPoint, format); // label length must be less than the length of the line if (sizeF.Width / scaleFactor < length) { LinePath tempPart = new LinePath(); foreach (ICoordinate p in part.Vertices) tempPart.Vertices.Add(p); int vertexNumber = 0; ICoordinate centerPoint = getDistantPoint(tempPart.Vertices, length / 2, out vertexNumber); // if the point of the proposed mid-label misses the display area of the map, the inscription does not appear if (!viewBox.ContainsPoint(centerPoint)) return null; // simplify the line tempPart.Weed(sizeF.Height / scaleFactor / 2); //get the center point of the simplified line centerPoint = getDistantPoint(tempPart.Vertices, length / 2, out vertexNumber); List<double> leftPointsRotationDeltas = new List<double>(); List<double> rightPointsRotationDeltas = new List<double>(); // coordinates of points on the left of the middle of the inscription IList<ICoordinate> leftPoints = getLeftPoints(tempPart.Vertices, centerPoint, sizeF.Width / 2 / scaleFactor, vertexNumber, sizeF.Height / 2 / scaleFactor, leftPointsRotationDeltas); // coordinates of the points to the right of the middle of the inscription IList<ICoordinate> rightPoints = getRightPoints(tempPart.Vertices, centerPoint, sizeF.Width / 2 / scaleFactor, vertexNumber, sizeF.Height / 2 / scaleFactor, rightPointsRotationDeltas); //coordinates of the vertices of the broken line, which will be located along the inscription List<ICoordinate> points = leftPoints.ToList(); points.AddRange(rightPoints); // shifts of the inscriptions associated with break lines List<double> rotationDeltas = leftPointsRotationDeltas; rotationDeltas.AddRange(rightPointsRotationDeltas); for (int i = 0; i < points.Count; i++) points[i] = PlanimetryEnvironment.NewCoordinate((points[i].X - viewBox.MinX) * scaleFactor, (viewBox.MaxY - points[i].Y) * scaleFactor); for (int i = 0; i < rotationDeltas.Count; i++) rotationDeltas[i] = rotationDeltas[i] * scaleFactor; //determine the direction of following labels (direct or reverse) double forwardWeight = 0; double backwardWeight = 0; for (int i = 1; i < points.Count; i++) { Segment s = new Segment(PlanimetryEnvironment.NewCoordinate(points[i].X, points[i].Y), PlanimetryEnvironment.NewCoordinate(points[i - 1].X, points[i - 1].Y)); int quadNumber = pointQuadrantNumber(PlanimetryEnvironment.NewCoordinate(s.V1.X - s.V2.X, s.V1.Y - s.V2.Y)); if (quadNumber == 1 || quadNumber == 4) forwardWeight += s.Length(); else backwardWeight += s.Length(); } if (backwardWeight > forwardWeight) { points.Reverse(); rotationDeltas.Reverse(); } // inscriptions along the route should not be a large number of points if (label.Length > points.Count - 2) { List<int> subStringLengths = new List<int>(); List<double> deltas = new List<double>(); LinePath p1 = new LinePath(points.ToArray()); double l = p1.Length(); // partition of the inscription on the straight parts, the calculation of displacement int startIndex = 0; for (int i = 1; i < points.Count; i++) { double currentDistance = PlanimetryAlgorithms.Distance(points[i - 1], points[i]); if (deltas.Count > 0) if (deltas[deltas.Count - 1] < currentDistance) currentDistance -= deltas[deltas.Count - 1]; //subtract the offset associated with line breaks currentDistance -= rotationDeltas[i - 1]; if (i < rotationDeltas.Count) currentDistance -= rotationDeltas[i]; int currentLength = (int)(currentDistance / l * label.Length); if (startIndex + currentLength > label.Length) currentLength = label.Length - startIndex; subStringLengths.Add(currentLength > 0 ? currentLength : 0); string subString; if (subStringLengths[i - 1] > 0) subString = label.Substring(startIndex, subStringLengths[i - 1]); else subString = string.Empty; float width1, width2, width3; width1 = width2 = width3 = g.MeasureString(subString, f, zeroPoint, format).Width; if (!string.IsNullOrEmpty(subString)) { if (subStringLengths[i - 1] > 1) { width2 = g.MeasureString(label.Substring(startIndex, subStringLengths[i - 1] - 1), f, zeroPoint, format).Width; if (Math.Abs(width2 - currentDistance) < Math.Abs(width1 - currentDistance)) { subStringLengths[i - 1] = subStringLengths[i - 1] - 1; width1 = width2; } } if (label.Length > subStringLengths[i - 1] + startIndex) { width3 = g.MeasureString(label.Substring(startIndex, subStringLengths[i - 1] + 1), f, zeroPoint, format).Width; if (Math.Abs(width3 - currentDistance) < Math.Abs(width1 - currentDistance) && Math.Abs(width3 - currentDistance) < sizeF.Width / label.Length / 6) { subStringLengths[i - 1] = subStringLengths[i - 1] + 1; width1 = width3; } } } deltas.Add(0.5 * (width1 - currentDistance)); if (currentLength > 0) startIndex += currentLength; } int sum = 0; int maxZeroLengths = 0; int zeroLengthsCount = 0; foreach (int k in subStringLengths) { if (k <= 0) { zeroLengthsCount++; if (maxZeroLengths < zeroLengthsCount) maxZeroLengths = zeroLengthsCount; } else zeroLengthsCount = 0; sum += k; } if (maxZeroLengths > 1) return null; int lastIndex = subStringLengths.Count() - 1; if (lastIndex >= 0) { subStringLengths[lastIndex] += label.Length - sum; if (subStringLengths[lastIndex] < 0) { subStringLengths[lastIndex - 1] -= subStringLengths[lastIndex]; subStringLengths[lastIndex] = 0; } } FollowingTitle followingTitle = new FollowingTitle(); startIndex = 0; double? previousAngle = null; for (int i = 0; i < subStringLengths.Count(); i++) { if (subStringLengths[i] <= 0) continue; if (startIndex + subStringLengths[i] > label.Length) return null; SizeF size; size = g.MeasureString(label.Substring(startIndex, subStringLengths[i]), f, zeroPoint, format); int x0 = (i == 0 ? 0 : (int)Math.Round(deltas[i - 1] + rotationDeltas[i - 1])); PointF[] v = new PointF[4]; v[0].X = x0; v[0].Y = -size.Height / 2; v[1].X = size.Width + x0; v[1].Y = -size.Height / 2; v[2].X = size.Width + x0; v[2].Y = size.Height / 2; v[3].X = x0; v[3].Y = size.Height / 2; float angle = (float)(180 / Math.PI * getAngle(PlanimetryEnvironment.NewCoordinate(Math.Abs(points[i].X * 2), points[i].Y), points[i], points[i + 1], false)); if (previousAngle != null) { double angleDelta = Math.Abs(angle - previousAngle.Value); if (angleDelta > 45 && 360 - angleDelta > 45) return null; } previousAngle = angle; g.TranslateTransform((float)points[i].X, (float)points[i].Y); g.RotateTransform(-(angle % 360)); g.Transform.TransformPoints(v); for (int j = 0; j < 4; j++) { v[j].X = (float)(v[j].X / scaleFactor + viewBox.MinX); v[j].Y = (float)(viewBox.MaxY - v[j].Y / scaleFactor); } FollowingTitleElement element = new FollowingTitleElement(new PointF((float)points[i].X, (float)points[i].Y), -(angle % 360), new PointF(x0, -size.Height / 2), label.Substring(startIndex, subStringLengths[i]), v[0], v[1], v[2], v[3]); startIndex += subStringLengths[i]; followingTitle.AddElement(element); g.ResetTransform(); } return followingTitle.EnvelopePolygon == null ? null : followingTitle; } } } return null; }
private void addTitleBufferElement(TitleStyle titleStyle, ICoordinate targetPoint, SizeF size, double scaleFactor, Feature feature) { _titleBuffer.Add(new TitleBufferElement(titleStyle, new Segment(targetPoint.X - size.Width / scaleFactor / 2, targetPoint.Y - size.Height / scaleFactor / 2, targetPoint.X + size.Width / scaleFactor / 2, targetPoint.Y + size.Height / scaleFactor / 2), feature.Title, _titleCount++)); }
private void addTitleBufferElement(Graphics g, Feature feature, TitleStyle titleStyle, BoundingRectangle viewBox, double scaleFactor) { ICoordinate targetCoordinate = PlanimetryEnvironment.NewCoordinate(0, 0); Segment s; SizeF size; using (Font f = titleStyle.GetFont()) size = g.MeasureString(feature.Title, f, new PointF(0, 0), _titleStringFormat); switch (feature.FeatureType) { case FeatureType.Polyline: if (!titleStyle.LeadAlong) { foreach (LinePath path in feature.Polyline.Paths) { if (path.Vertices.Count > 2) targetCoordinate = path.Vertices[path.Vertices.Count / 2 - 1]; else { s = new Segment(path.Vertices[0].X, path.Vertices[0].Y, path.Vertices[1].X, path.Vertices[1].Y); targetCoordinate = s.Center(); } addTitleBufferElement(titleStyle, targetCoordinate, size, scaleFactor, feature); } } else { int i = 0; foreach (LinePath path in feature.Polyline.Paths) { FollowingTitle followingTitle = getFollowingTitle(g, path, feature.PolylinePartLengths[i], feature.Title, titleStyle, viewBox, scaleFactor); if (followingTitle != null) _titleBuffer.Add(new TitleBufferElement(followingTitle, titleStyle, _titleCount++)); i++; } } return; case FeatureType.Polygon: //if (feature.Polygon.Contours.Count > 0) // targetPoint = feature.Polygon.Contours[0].RibsCentroid(); //else // return; //break; if (feature.Polygon.Contours.Count > 0) try { targetCoordinate = feature.Polygon.PointOnSurface(); } catch(InvalidOperationException) { //interior point of the polygon for some reason (usually singular) can not be found return; } else return; break; case FeatureType.Point: targetCoordinate = feature.Point.Coordinate; //targetPoint.Y += size.Height / scaleFactor / 2; break; case FeatureType.MultiPoint: if (titleStyle.LeadAlong) { foreach (ICoordinate p in feature.MultiPoint.Points) { targetCoordinate = p; targetCoordinate.Y += size.Height / scaleFactor / 2; addTitleBufferElement(titleStyle, targetCoordinate, size, scaleFactor, feature); } return; } else targetCoordinate = PlanimetryAlgorithms.GetCentroid(feature.MultiPoint.Points); break; } addTitleBufferElement(titleStyle, targetCoordinate, size, scaleFactor, feature); }
/// <summary/> protected void processTitleStyle(XmlNode layerNode, TitleStyle TitleStyle) { XmlNode titleStyle = tryGetNodeByName(layerNode.ChildNodes, "title_style"); if (titleStyle != null) { TitleStyle.TitlesVisible = titleStyle.Attributes["visible"].Value == "1"; if (titleStyle.Attributes["visible_scale"] != null) TitleStyle.VisibleScale = double.Parse(titleStyle.Attributes["visible_scale"].Value, CultureInfo.InvariantCulture); TitleStyle.Color = ColorTranslator.FromHtml(titleStyle.Attributes["color"].Value); TitleStyle.FontFamily = titleStyle.Attributes["font_name"].Value; TitleStyle.FontSize = float.Parse(titleStyle.Attributes["font_size"].Value, CultureInfo.InvariantCulture); TitleStyle.FontStyle = (FontStyle)int.Parse(titleStyle.Attributes["font_style"].Value, CultureInfo.InvariantCulture); if (titleStyle.Attributes["render_priority"] != null) TitleStyle.RenderPriority = int.Parse(titleStyle.Attributes["render_priority"].Value, CultureInfo.InvariantCulture); if (titleStyle.Attributes["use_outline"] != null) TitleStyle.UseOutline = titleStyle.Attributes["use_outline"].Value == "1"; if (titleStyle.Attributes["outline_size"] != null) TitleStyle.OutlineSize = int.Parse(titleStyle.Attributes["outline_size"].Value, CultureInfo.InvariantCulture); if (titleStyle.Attributes["lead_along"] != null) TitleStyle.LeadAlong = titleStyle.Attributes["lead_along"].Value == "1"; } }