Example #1
0
        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;
        }
Example #2
0
 public static double Adjustment(MathNode script)
 {
     if (script.AlignToAxis)
     {
         return(script.Axis());
     }
     else
     {
         return(0);
     }
 }
Example #3
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;
            }
        }
Example #4
0
        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);
        }
Example #5
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;
            }
        }
Example #6
0
 public static double Adjustment(MathNode script)
 {
     if (script.AlignToAxis)
         return script.Axis();
     else
         return 0;
 }
Example #7
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;
                }
            }
        }
Example #8
0
        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();
        }