public static XElement DrawImage(MathNode node) { //Top-level draw function: prepare the canvas, then call the draw method of the root node double baseline = 0; if (node.AlignToAxis) baseline = node.Axis(); double height = Math.Max(node.Height, node.Ascender); double depth = Math.Max(node.Depth, node.Descender); double vsize = height + depth; Dictionary<string, string> attrs = new Dictionary<string, string>(){ {"width", string.Format("{0:F6}pt", node.Width)}, {"height", string.Format("{0:F6}pt", vsize)}, {"viewBox", string.Format("0 {0:F6} {1:F6} {2:F6}", (-(height+baseline)), node.Width, vsize)} }; XElement nodeElement = creatElement("svg", attrs); nodeElement.SetAttributeValue(XNamespace.Xmlns + "svg", SvgNs.NamespaceName); nodeElement.SetAttributeValue(XNamespace.Xmlns + "svgmath", SvgMathNs.NamespaceName); XElement metadataElement = creatElement("metadata", null, false); XElement metricElement = creatElement("metrics", new Dictionary<string, string>(){ {"baseline", string.Format("{0}", depth - baseline)}, {"axis", string.Format("{0}", depth - baseline + node.Axis())}, {"top", string.Format("{0}", depth + node.Height)}, {"bottom", string.Format("{0}", depth - node.Depth)} }, true); metadataElement.Add(metricElement); nodeElement.Add(metadataElement); DrawTranslatedNode(node, nodeElement, 0, -baseline); return nodeElement; }
public static double Adjustment(MathNode script) { if (script.AlignToAxis) { return(script.Axis()); } else { return(0); } }
public static void GMRow(MathNode node, XElement output) { DrawBox(node, output); if (node.Children.Count == 0) return; double offset = -node.Children.First().LeftSpace; foreach (MathNode ch in node.Children) { offset += ch.LeftSpace; double baseline = 0; if (ch.AlignToAxis && !node.AlignToAxis) //ToDo: might not behave the same as Python since aligntoaxis might be none baseline = -node.Axis(); DrawTranslatedNode(ch, output, offset, baseline); offset += ch.Width + ch.RightSpace; } }
public static XElement DrawImage(MathNode node) { //Top-level draw function: prepare the canvas, then call the draw method of the root node double baseline = 0; if (node.AlignToAxis) { baseline = node.Axis(); } double height = Math.Max(node.Height, node.Ascender); double depth = Math.Max(node.Depth, node.Descender); double vsize = height + depth; Dictionary <string, string> attrs = new Dictionary <string, string>() { { "width", string.Format(CultureInfo.InvariantCulture, "{0:F6}pt", node.Width) }, { "height", string.Format(CultureInfo.InvariantCulture, "{0:F6}pt", vsize) }, { "viewBox", string.Format(CultureInfo.InvariantCulture, "0 {0:F6} {1:F6} {2:F6}", (-(height + baseline)), node.Width, vsize) } }; XElement nodeElement = creatElement("svg", attrs); nodeElement.SetAttributeValue(XNamespace.Xmlns + "svg", SvgNs.NamespaceName); nodeElement.SetAttributeValue(XNamespace.Xmlns + "svgmath", SvgMathNs.NamespaceName); XElement metadataElement = creatElement("metadata", null, false); XElement metricElement = creatElement("metrics", new Dictionary <string, string>() { { "baseline", string.Format(CultureInfo.InvariantCulture, "{0}", depth - baseline) }, { "axis", string.Format(CultureInfo.InvariantCulture, "{0}", depth - baseline + node.Axis()) }, { "top", string.Format(CultureInfo.InvariantCulture, "{0}", depth + node.Height) }, { "bottom", string.Format(CultureInfo.InvariantCulture, "{0}", depth - node.Depth) } }, true); metadataElement.Add(metricElement); nodeElement.Add(metadataElement); DrawTranslatedNode(node, nodeElement, 0, -baseline); return(nodeElement); }
public static void GMRow(MathNode node, XElement output) { DrawBox(node, output); if (node.Children.Count == 0) { return; } double offset = -node.Children.First().LeftSpace; foreach (MathNode ch in node.Children) { offset += ch.LeftSpace; double baseline = 0; if (ch.AlignToAxis && !node.AlignToAxis) //ToDo: might not behave the same as Python since aligntoaxis might be none { baseline = -node.Axis(); } DrawTranslatedNode(ch, output, offset, baseline); offset += ch.Width + ch.RightSpace; } }
public static double Adjustment(MathNode script) { if (script.AlignToAxis) return script.Axis(); else return 0; }
void CalculateRowHeights(MathNode node) { //Set initial row heights for cells with rowspan == 1 double commonAxis = node.Axis(); foreach(RowDescriptor r in node.Rows) { r.Height = 0; r.Depth = 0; foreach (CellDescriptor c in r.Cells) { if (c == null || c.Content == null || c.RowSpan != 1) continue; double cellAxis = c.Content.Axis(); c.VShift = 0; if (c.VAlign == "baseline") { if (r.AlignToAxis == true) c.VShift -= commonAxis; if (c.Content.AlignToAxis == true) c.VShift += cellAxis; } else if (c.VAlign == "axis") { if (!r.AlignToAxis) c.VShift += commonAxis; if (!c.Content.AlignToAxis) c.VShift -= cellAxis; } else { c.VShift = (r.Height - r.Depth - c.Content.Height + c.Content.Depth) / 2; } r.Height = Math.Max(r.Height, c.Content.Height + c.VShift); r.Depth = Math.Max(r.Depth, c.Content.Depth - c.VShift); } } // Calculate heights for cells with rowspan > 1 while (true) { List<RowDescriptor> adjustedRows = new List<RowDescriptor>(); double adjustedSize = 0; foreach (var item in node.Rows.Select((value,i) => new {i, value})) { RowDescriptor r = item.value; foreach (CellDescriptor c in r.Cells) { if (c == null || c.Content == null || c.RowSpan == 1) continue; List<RowDescriptor> rows = node.Rows.Skip(item.i).Take(item.i + c.RowSpan).ToList(); double requiredSize = c.Content.Height + c.Content.Depth; requiredSize -= rows.Where((value, i) => i < rows.Count).Select(x=> x.SpaceAfter).Sum(); double fullSize = rows.Select(x=> x.Height+x.Depth).Sum(); if (fullSize >= requiredSize) continue; double unitSize = requiredSize / rows.Count; while (true) { List<RowDescriptor> oversizedRows = rows.Where(x => x.Height + x.Depth > unitSize).ToList(); //ToDo: Verify if (oversizedRows.Count == 0) break; rows = rows.Where(x => x.Height + x.Depth < unitSize).ToList(); if (rows.Count == 0) break; // weird rounding effects requiredSize -= oversizedRows.Select(x => x.Height + x.Depth).Sum(); unitSize = requiredSize / rows.Count; } if (rows.Count == 0) continue; // protection against arithmetic overflow if (unitSize > adjustedSize) { adjustedSize = unitSize; adjustedRows = rows; } } } if (adjustedRows.Count == 0) break; foreach (RowDescriptor r in adjustedRows) { double delta = (adjustedSize - r.Height - r.Depth) / 2; r.Height += delta; r.Depth += delta; } } if (node.GetProperty("equalrows") == "true") { double maxvsize = node.Rows.Select(x => x.Height + x.Depth).Max(); foreach (RowDescriptor r in node.Rows) { double delta = (maxvsize - r.Height - r.Depth) / 2; r.Height += delta; r.Depth += delta; } } }
private void MeasureScripts(MathNode node, List<MathNode> subscripts, List<MathNode> superscripts, List<MathNode> presubscripts = null, List<MathNode> presuperscripts = null) { node.SubScripts = subscripts == null ? new List<MathNode>() : subscripts; node.SuperScripts = superscripts == null ? new List<MathNode>() : superscripts; node.PreSubScripts = presubscripts == null ? new List<MathNode>() : presubscripts; node.PreSuperScripts = presuperscripts == null ? new List<MathNode>() : presuperscripts; SetNodeBase(node, node.Children[0]); node.Width = node.Base.Width; node.Height = node.Base.Height; node.Depth = node.Base.Depth; node.Ascender = node.Base.Ascender; node.Descender = node.Base.Descender; List<MathNode> both_subs = new List<MathNode>(node.SubScripts); both_subs.AddRange(node.PreSubScripts); List<MathNode> both_sups = new List<MathNode>(node.SuperScripts); both_sups.AddRange(node.PreSuperScripts); node.SubScriptAxis = both_subs.Select(x => x.Axis()).Union(new List<double>() { 0 }).Max(); node.SuperScriptAxis = both_sups.Select(x => x.Axis()).Union(new List<double>() { 0 }).Max(); List<MathNode> all = new List<MathNode>(both_subs); all.AddRange(both_sups); double gap = all.Select(x => x.NominalLineGap()).Max(); //ToDo:Validate double protrusion = node.ParseLength("0.25ex"); double scriptMedian = node.Axis(); double[] v = GetRowVerticalExtent(both_subs, false, node.SubScriptAxis); double subHeight = v[0]; double subDepth = v[1]; double subAscender = v[2]; double subDescender = v[3]; v = GetRowVerticalExtent(both_sups, false, node.SuperScriptAxis); double superHeight = v[0]; double superDepth = v[1]; double superAscender = v[2]; double superDescender = v[3]; node.SubShift = 0; if (both_subs.Count > 0) { string shiftAttr = node.GetProperty("subscriptshift"); if (shiftAttr == null) shiftAttr = "0.5ex"; node.SubShift = node.ParseLength(shiftAttr); // positive shifts down node.SubShift = Math.Max(node.SubShift, subHeight - scriptMedian + gap); if (node.AlignToAxis) node.SubShift += node.Axis(); node.SubShift = Math.Max(node.SubShift, node.Base.Depth + protrusion - subDepth); node.Height = Math.Max(node.Height, subHeight - node.SubShift); node.Depth = Math.Max(node.Depth, subDepth + node.SubShift); node.Ascender = Math.Max(node.Ascender, subAscender - node.SubShift); node.Descender = Math.Max(node.Descender, subDescender + node.SubShift); } node.SuperShift = 0; if (both_sups.Count > 0) { string shiftAttr = node.GetProperty("superscriptshift"); if (shiftAttr == null) shiftAttr = "1ex"; node.SuperShift = node.ParseLength(shiftAttr); // positive shifts up node.SuperShift = Math.Max(node.SuperShift, superDepth + scriptMedian + gap); if (node.AlignToAxis) node.SuperShift -= node.Axis(); node.SuperShift = Math.Max(node.SuperShift, node.Base.Height + protrusion - superHeight); node.Height = Math.Max(node.Height, superHeight + node.SuperShift); node.Depth = Math.Max(node.Depth, superDepth - node.SuperShift); node.Ascender = Math.Max(node.Ascender, superHeight + node.SuperShift); node.Descender = Math.Max(node.Descender, superDepth - node.SuperShift); } node.PostWidths = ParallelWidths(node.SubScripts, node.SuperScripts); node.PreWidths = ParallelWidths(node.PreSubScripts, node.PreSuperScripts); node.Width += node.PreWidths.Sum() + node.PostWidths.Sum(); }