From 7cf3480ac7a715c643b2cdf012fc386c39d4538f Mon Sep 17 00:00:00 2001 From: SheepRock Date: Wed, 21 Jun 2017 13:04:22 -0300 Subject: [PATCH] Added equation creation extensions Added file Equation.cs with Equation class, which allows an easy way to create complex equation. Added file ExtensionsEquations.cs which contains an extension that allow the insertion of Equation paragraphs. --- DocX/Equation.cs | 569 ++++++++++++++++++++++++++++++++++++ DocX/ExtensionsEquations.cs | 25 ++ 2 files changed, 594 insertions(+) create mode 100644 DocX/Equation.cs create mode 100644 DocX/ExtensionsEquations.cs diff --git a/DocX/Equation.cs b/DocX/Equation.cs new file mode 100644 index 00000000..1d4ecc60 --- /dev/null +++ b/DocX/Equation.cs @@ -0,0 +1,569 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using Novacode; + +namespace OMath +{ + public class Equation + { + private static XNamespace mathNamespace = "http://schemas.openxmlformats.org/officeDocument/2006/math"; + private static XNamespace wordNamespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; + + + private XElement xml; + public XElement Xml { get => xml; set => xml = value; } + + #region Constructors + + private Equation(XElement el) + { + Xml = new XElement(mathNamespace + "oMath", el); + } + public Equation() + { + Xml = new XElement(mathNamespace + "oMath"); + } + public Equation(string content) + { + Xml = new XElement(mathNamespace + "oMath", CreateLiteral(content)); + } + + #endregion + + + #region Operators + + public static implicit operator Equation(string content) + { + Equation eq = new Equation(); + eq.AppendElement(CreateLiteral(content)); + return eq; + } + public static Equation operator +(Equation eq1, Equation eq2) + { + Equation eq = new Equation(); + eq.Append(eq1); + eq.Append("+"); + eq.Append(eq2); + return eq; + } + public static Equation operator -(Equation eq1, Equation eq2) + { + Equation eq = new Equation(); + eq.Append(eq1); + eq.Append("-"); + eq.Append(eq2); + return eq; + } + public static Equation operator *(Equation eq1, Equation eq2) + { + Equation eq = new Equation(); + eq.Append(eq1); + eq.Append("*"); + eq.Append(eq2); + return eq; + } + public static Equation operator /(Equation eq1, Equation eq2) + { + return Equation.Fraction(eq1, eq2); + } + + #endregion + + #region Methods + /// + /// Append and xml element to the object xml + /// + /// + public void AppendElement(XElement content) + { + Xml.Add(content); + } + /// + /// Append an equation to the current equation + /// + /// Equation to append + public void Append(Equation content) + { + Xml.Add(content.Xml.Elements()); + } + #endregion + + #region Equation Creation + private static XElement CreateLiteral(object literal) + { + XElement lit = new XElement(mathNamespace + "r"); + XElement rPr = new XElement(wordNamespace + "rPr"); + XElement rFonts = new XElement(wordNamespace + "rFonts"); + + rFonts.Add(new XAttribute(wordNamespace + "ascii", "Cambria Math")); + rFonts.Add(new XAttribute(wordNamespace + "hAnsi", "Cambria Math")); + rPr.Add(rFonts); + lit.Add(rPr); + lit.Add(new XElement(mathNamespace + "t", literal)); + return lit; + } + + private static XElement CreateBox(object content) + { + XElement borderBox = new XElement(mathNamespace + "borderBox"); + borderBox.Add(new XElement(mathNamespace + "e", content)); + return borderBox; + } + /// + /// Creates a Box around the equation + /// + /// Content of the Box + /// + public static Equation Box(Equation content) + { + return new Equation(CreateBox(content.Xml.Elements())); + } + + #region Parenthesis + private static XElement CreateParenthesis(object content, char opening = '(', char closing = ')') + { + XElement parenthesis = new XElement(mathNamespace + "d"); + + if (opening != '(' || closing != ')') + { + XElement dPr = new XElement(mathNamespace + "dPr"); + XElement begChr = new XElement(mathNamespace + "begChr", new XAttribute(mathNamespace + "val", opening.ToString())); + XElement endChr = new XElement(mathNamespace + "endChr", new XAttribute(mathNamespace + "val", closing.ToString())); + dPr.Add(begChr); + dPr.Add(endChr); + parenthesis.Add(dPr); + } + XElement _content = new XElement(mathNamespace + "e", content); + parenthesis.Add(_content); + + return parenthesis; + } + /// + /// Creates parenthesis, brackets and other types of enclousures + /// + /// Equation inside the enclousure + /// Opening char for the enclousure. Default is '(' + /// Closing char for the enclousure. Default is ')' + /// + public static Equation Parenthesis(Equation content, char opening = '(', char closing = ')') + { + return new Equation(CreateParenthesis(content, opening, closing)); + } + #endregion + + #region Root + private static XElement CreateRoot(object radicand, object degree = null) + { + XElement rad = new XElement(mathNamespace + "rad"); + + XElement deg = new XElement(mathNamespace + "deg"); + if (degree == null) + { + XElement radProp = new XElement(mathNamespace + "radPr"); + XElement degHide = new XElement(mathNamespace + "degHide"); + degHide.Add(new XAttribute(mathNamespace + "val", 1)); + radProp.Add(degHide); + rad.Add(radProp); + } + else + { + deg.Add(degree); + } + rad.Add(deg); + + XElement content = new XElement(mathNamespace + "e", radicand); + //content.Add(new XElement(mathNamespace + "r", new XElement(mathNamespace + "t", radicand))); + rad.Add(content); + + return rad; + } + /// + /// Creates a n degree root + /// + /// Radicand of the root + /// Degree of the root + /// + public static Equation Root(Equation radicand, Equation degree) + { + Equation eq = new Equation(CreateRoot(radicand.Xml.Elements(), degree.Xml.Elements())); + return eq; + } + /// + /// Creates a square root + /// + /// Content of the square root + /// + public static Equation Root(Equation radicand) + { + Equation eq = new Equation(CreateRoot(radicand.Xml.Elements())); + return eq; + } + #endregion + + #region Fraction + private static XElement CreateFraction(object num, object den) + { + XElement numerator = new XElement(mathNamespace + "num", num); + + XElement denominator = new XElement(mathNamespace + "den", den); + + XElement fraction = new XElement(mathNamespace + "f"); + fraction.Add(numerator); + fraction.Add(denominator); + return fraction; + } + /// + /// Creates a fraction + /// + /// Numerator of the fraction + /// Denominator of the fraction + /// + public static Equation Fraction(Equation num, Equation den) + { + Equation eq = new Equation(); + eq.AppendElement(CreateFraction(num.Xml.Elements(), den.Xml.Elements())); + return eq; + } + #endregion + + #region SuperSubscripts + private static XElement CreateSuperscript(object content, object superior) + { + XElement sSup = new XElement(mathNamespace + "sSup"); + XElement e = new XElement(mathNamespace + "e", content); + XElement sup = new XElement(mathNamespace + "sup", superior); + sSup.Add(e); + sSup.Add(sup); + return sSup; + } + /// + /// Creates a superscript + /// + /// Base element + /// Expoent + /// + public static Equation Superscript(Equation content, Equation superior) + { + return new Equation(CreateSuperscript(content.Xml.Elements(), superior.Xml.Elements())); + } + + private static XElement CreateSubscript(object content, object inferior) + { + XElement sSub = new XElement(mathNamespace + "sSub"); + XElement e = new XElement(mathNamespace + "e", content); + XElement sub = new XElement(mathNamespace + "sub", inferior); + sSub.Add(e); + sSub.Add(sub); + return sSub; + } + /// + /// Creates a subscript + /// + /// Base element + /// subscript + /// + public static Equation Subscript(Equation content, Equation inferior) + { + return new Equation(CreateSubscript(content.Xml.Elements(), inferior.Xml.Elements())); + } + + private static XElement CreateSubSuperscript(object content, object inferior, object superior) + { + XElement sSubSup = new XElement(mathNamespace + "sSubSup"); + XElement e = new XElement(mathNamespace + "e", content); + XElement sub = new XElement(mathNamespace + "sub", inferior); + XElement sup = new XElement(mathNamespace + "sup", superior); + sSubSup.Add(e); + sSubSup.Add(sub); + sSubSup.Add(sup); + return sSubSup; + } + /// + /// Creates an element with a superscript and a subscript + /// + /// Base element + /// Subscript + /// Expoent + /// + public static Equation SubSuperscript(Equation content, Equation inferior, Equation superior) + { + return new Equation(CreateSubSuperscript(content.Xml.Elements(),inferior.Xml.Elements(), superior.Xml.Elements())); + } + + private static XElement CreatePrescript(object content, object inferior, object superior) + { + XElement sPre = new XElement(mathNamespace + "sPre"); + XElement e = new XElement(mathNamespace + "e", content); + XElement sub = new XElement(mathNamespace + "sub", inferior); + XElement sup = new XElement(mathNamespace + "sup", superior); + sPre.Add(sub); + sPre.Add(sup); + sPre.Add(e); + return sPre; + } + /// + /// Creates an element with a superscrit and a subscript before the base element + /// + /// Base element + /// Subscript + /// Superscript + /// + public static Equation Prescript(Equation content, Equation inferior, Equation superior) + { + return new Equation(CreateSubSuperscript(content.Xml.Elements(), inferior.Xml.Elements(), superior.Xml.Elements())); + } + #endregion + + #region Integral, Sums, Products + public enum IntegralPosition { Top, Front }; + public enum IntegralType { Simple, Double, Triple, Line, Surface, Volume, Sum, Product, Union, Intersection, Disjunction, Conjunction } + private static Dictionary integralTypeDictionary = new Dictionary() + { + {IntegralType.Simple,' ' }, + {IntegralType.Double,'∬' }, + {IntegralType.Triple,'∭' }, + {IntegralType.Line,'∮' }, + {IntegralType.Surface,'∯' }, + {IntegralType.Volume,'∰' }, + {IntegralType.Sum,'∑' }, + {IntegralType.Product,'∏' }, + {IntegralType.Union,'⋃' }, + {IntegralType.Intersection,'⋂' }, + {IntegralType.Disjunction,'⋁' }, + {IntegralType.Conjunction,'⋀' } + }; + private static XElement CreateIntegral(object content, object inferior = null, object superior = null, string position = "undOvr", char chr = ' ') + { + XElement nary = new XElement(mathNamespace + "nary"); + XElement naryPr = new XElement(mathNamespace + "naryPr"); + if (chr != ' ') + { + naryPr.Add( + new XElement( + mathNamespace + "chr", + new XAttribute( + mathNamespace + "val", + chr + ))); + } + naryPr.Add( + new XElement( + mathNamespace + "limLoc", + new XAttribute( + mathNamespace + "val", + position + ))); + if (inferior == null) + { + naryPr.Add( + new XElement( + mathNamespace + "subHide", + new XAttribute( + mathNamespace + "val", + "1" + ))); + + } + else + { + nary.Add(new XElement(mathNamespace + "sub", inferior)); + } + if (superior == null) + { + naryPr.Add( + new XElement( + mathNamespace + "supHide", + new XAttribute( + mathNamespace + "val", + "1" + ))); + } + else + { + nary.Add(new XElement(mathNamespace + "sup", superior)); + } + nary.Add(naryPr); + nary.Add(new XElement(mathNamespace + "e", content)); + return nary; + } + /// + /// Creates integrals, sums, products, union, intersection, disjuntion or cojunction + /// + /// Content of the equation + /// Bottom limit. To hide, use null. Default is null + /// Upper limit. To hide, use null. Default is null + /// Position of limits, could be Top for above and bellow the symbol, + /// or Front, to be in front of the symbol + /// Symbol for the equation. Default is Simple (Integral) + /// + public static Equation Integral(Equation content, Equation inferior=null, Equation superior=null, IntegralPosition position=IntegralPosition.Front, IntegralType it = IntegralType.Simple) + { + string pos = position == IntegralPosition.Top ? "undOvr" : "subSup"; + return new Equation(CreateIntegral(content.Xml.Elements(), inferior.Xml.Elements(), superior.Xml.Elements(), pos, integralTypeDictionary[it])); + } + #endregion + + #region Matrix + private static XElement CreateMatrix(object[,] content) + { + XElement m = new XElement(mathNamespace + "m"); + int columns = content.GetLength(1); + XElement mPr = new XElement(mathNamespace + "mPr", + new XElement(mathNamespace+"mcs", + new XElement(mathNamespace+"mc", + new XElement(mathNamespace+"mcPr", + new XElement(mathNamespace+"count", + new XAttribute(mathNamespace+"val",columns)), + new XElement(mathNamespace + "mcJc", + new XAttribute(mathNamespace + "val", "center") + ))))); + m.Add(mPr); + for(int row = 0; row < content.GetLength(0); row++) + { + XElement mr = new XElement(mathNamespace + "mr"); + for(int col = 0; col < columns; col++) + { + mr.Add(new XElement(mathNamespace + "e", content[row, col])); + } + m.Add(mr); + } + return m; + } + /// + /// Creates a matrix + /// + /// Bidimensional array with the elements of the matrix + /// + public static Equation Matrix(Equation[,] content) + { + object[,] mat = new object[content.GetLength(0), content.GetLength(1)]; + for(int r=0;r< content.GetLength(0); r++) + { + for (int c = 0; c < content.GetLength(1); c++) + { + mat[r, c] = content[r, c].Xml.Elements(); + } + } + return new Equation(CreateMatrix(mat)); + } + #endregion + + #region Enfasis + private static XElement CreateEnfasis(object content, char enf=' ') + { + XElement acc = new XElement(mathNamespace + "acc"); + if (enf!=' ') + { + XElement accPr = new XElement(mathNamespace + "accPr"); + accPr.Add(new XElement(mathNamespace + "chr", new XAttribute(mathNamespace + "val", enf))); + acc.Add(accPr); + } + acc.Add(new XElement(mathNamespace + "e", content)); + return acc; + } + /// + /// Creates a element with a char above + /// + /// The base element + /// The char above the base element + /// + public static Equation Enfasis(Equation content, char enf) + { + return new Equation(CreateEnfasis(content.Xml.Elements(), enf)); + } + #endregion + + #region Limit + public enum LimitPosition { Bottom, Top }; + private static XElement CreateLimit(object content, object limit, LimitPosition limitPosition=LimitPosition.Bottom) + { + string type = limitPosition == LimitPosition.Top ? "limUpp" : "limLow"; + XElement lim = new XElement(mathNamespace + type); + lim.Add(new XElement(mathNamespace + "e", content)); + lim.Add(new XElement(mathNamespace + "lim", limit)); + return lim; + } + /// + /// Creates an element with an element below in a smaller font + /// + /// Base element + /// Smaller font element + /// + public static Equation Limit(Equation content, Equation limit) + { + return new Equation(CreateLimit(content.Xml.Elements(), limit.Xml.Elements())); + } + /// + /// Creates an element with an element above or below in a smaller font + /// + /// Base element + /// Smaller font element + /// Position of the smaller element + /// + public static Equation Limit(Equation content, Equation limit, LimitPosition limitPosition) + { + return new Equation(CreateLimit(content.Xml.Elements(), limit.Xml.Elements(),limitPosition)); + } + #endregion + + #region Function + private static XElement CreateFunction(XElement name, object argument) + { + XElement func = new XElement(mathNamespace + "func"); + + foreach (var n in name.Descendants(mathNamespace + "r")) + { + XElement rPr = n.Element(mathNamespace + "rPr"); + if (rPr == null) + { + n.AddFirst(new XElement(mathNamespace + "rPr")); + rPr = n.Element(mathNamespace + "rPr"); + } + rPr.Add(new XElement(mathNamespace + "sty", new XAttribute(mathNamespace + "val", "p"))); + } + func.Add(new XElement(mathNamespace + "fName", name)); + + func.Add(new XElement(mathNamespace + "e", argument)); + return func; + } + private static XElement CreateFunction(IEnumerable name, object argument) + { + XElement func = new XElement(mathNamespace + "func"); + foreach(var nam in name) + { + foreach (var n in nam.Descendants(mathNamespace + "r")) + { + XElement rPr = n.Element(mathNamespace + "rPr"); + if (rPr == null) + { + n.AddFirst(new XElement(mathNamespace + "rPr")); + rPr = n.Element(mathNamespace + "rPr"); + } + rPr.Add(new XElement(mathNamespace + "sty", new XAttribute(mathNamespace + "val", "p"))); + } + } + func.Add(new XElement(mathNamespace + "fName", name)); + func.Add(new XElement(mathNamespace + "e", argument)); + return func; + } + /// + /// Creates a function with a font name in normal font + /// and an argument with math style font in front of the name element + /// + /// Normal font element + /// Math font element + /// + public static Equation Function(Equation name, Equation argument) + { + return new Equation(CreateFunction(name.Xml.Elements(), argument.Xml.Elements())); + } + #endregion + + #endregion + } +} diff --git a/DocX/ExtensionsEquations.cs b/DocX/ExtensionsEquations.cs new file mode 100644 index 00000000..1f4b3327 --- /dev/null +++ b/DocX/ExtensionsEquations.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Novacode; +using System.Xml.Linq; + +namespace OMath +{ + public static class ExtensionsEquations + { + public static Novacode.Paragraph InsertEquation(this DocX doc, Equation equation) + { + Paragraph eqParagraph = doc.InsertEquation(""); + XElement xml = eqParagraph.Xml; + XNamespace mathNamespace = "http://schemas.openxmlformats.org/officeDocument/2006/math"; + XElement omath = xml.Descendants(mathNamespace + "oMathPara").First(); + omath.Elements().Remove(); + omath.Add(equation.Xml); + + return eqParagraph; + } + } +}