public Msubsup(IBuildable[] contents) { // handle star superscript List <IBuildable> localCopy = new List <IBuildable>(contents); if (localCopy.Count == 3) { Mo mo = localCopy[2] as Mo; if (mo != null && mo.IsTimesOrStar) { Mi subscript = localCopy[1] as Mi; if (subscript != null) { subscript.Content += Semantics.starPrefix; localCopy.RemoveAt(2); } else { // maybe the subscript is an mrow Mrow row = localCopy[1] as Mrow; if (row != null && row.LastElement != null && row.LastElement is WithTextContent) { WithTextContent lastElem = (WithTextContent)row.LastElement; lastElem.Content += Semantics.starPrefix; localCopy.RemoveAt(2); } } } } base.contents = localCopy.ToArray(); }
public override void Visit(StringBuilder sb, BuildContext bc) { if (bc.Options.SubscriptMode) { // separate by double underscore to differentiate from Msub and prevent clashes first.Visit(sb, bc); sb.Append("__"); second.Visit(sb, bc); } else if (second is Mo && (second as Mo).IsTimesOrStar && first is Mi) { // this isn't really a superscript - it's part of the variable Mi mi = (Mi)first; Mi newMi = new Mi(mi.Content + Semantics.starPrefix); newMi.Visit(sb, bc); } else { if (bc.LastTokenRequiresTimes) { sb.Append("*"); } // determine whether power must be inlined bool firstIsMrowMi = (first is Mrow) && ((first as Mrow).ContainsSingleMi); bool secondIsIntegralPower = (second is Mrow) && ((second as Mrow).ContainsSingleMn) && ((second as Mrow).LastElement as Mn).IsIntegerGreaterThan1; bool mustInlinePower = false; int power = 0; if (secondIsIntegralPower) { power = ((second as Mrow).LastElement as Mn).IntegerValue; mustInlinePower = power <= bc.Options.MaxInlinePower; } if (mustInlinePower) { for (int i = 0; i < power; ++i) { first.Visit(sb, bc); // * sign appended automatically } } else { sb.Append("Math.Pow("); first.Visit(sb, bc); sb.Append(", "); second.Visit(sb, bc); sb.Append(")"); } } bc.Tokens.Add(this); }
/// <summary> /// This function replaces all known inverse trig functions (in the msup blocks) /// by inverse names, so that sin^-1 becomes arcsin. /// </summary> /// <param name="contents">Buidlable contents</param> private static void ReplaceInverseTrigFunctions(IBuildable[] contents) { for (int i = 0; i < contents.Length; i++) { IBuildable c = contents[i]; string trigFunction = string.Empty; if (c is Msup) { bool funcIsTrig = false, radixIsNeg1 = false; Pair <IBuildable, IBuildable> terms = (c as Msup).Values; if (terms.First is Mrow) { Mrow row1 = terms.First as Mrow; if (row1.Contents.Length > 0 && row1.Contents[0] is Mi) { if (Semantics.inverseTrigs.ContainsKey((row1.Contents[0] as Mi).Content)) { trigFunction = (row1.Contents[0] as Mi).Content; funcIsTrig = true; } } } if (terms.Second is Mrow) { Mrow row2 = terms.Second as Mrow; StringBuilder sb = new StringBuilder(); BuildContext bc = new BuildContext(); row2.Visit(sb, bc); if (sb.ToString() == "-1") { radixIsNeg1 = true; } } // if this is an inverse function, replace an <msup> with an inverse <mi> if (funcIsTrig && radixIsNeg1) { Mi mi = new Mi(Semantics.inverseTrigs[trigFunction]); contents[i] = mi; } } } }
public virtual void Visit(StringBuilder sb, BuildContext context) { bool containsFunct = false; int numFuncts = 0; if (sb == null || context == null || contents == null || contents.Length == 0) { return; } // copy contents into list List <IBuildable> ctxCopy = new List <IBuildable>(contents); // check if the Sigma operator acts as a sum if (context.Options.TreatSigmaAsSum) { // look for the plain sigma operator int index; while ((index = ctxCopy.FindIndex(a => (a is Mo && (a as Mo).IsSigma))) != -1) { // so long as it is not the last element if (index != ctxCopy.Count - 1) { BuildablePlainSum bps = new BuildablePlainSum(ctxCopy[index + 1]); ctxCopy.RemoveAt(index + 1); ctxCopy[index] = bps; context.AddSum(bps); } } } // check if delta <mo> appears before an <mi> if (context.Options.DeltaPartOfIdent) { int index; while ((index = ctxCopy.FindIndex(a => (a is Mo && (a as Mo).IsDelta))) != -1) { // check that it's not the last element if (index != ctxCopy.Count - 1) { // check that the next element is <mi> Mi mi = ctxCopy[index + 1] as Mi; if (mi != null) { // change Mi's content to incorporate the delta Mi newMi = new Mi("∆" + mi.Content); ctxCopy[index + 1] = newMi; // remove the delta ctxCopy.RemoveAt(index); Trace.WriteLine(newMi.Content); } } } } else { // change delta from mo to mi int index; while ((index = ctxCopy.FindIndex(a => (a is Mo && (a as Mo).IsDelta))) != -1) { ctxCopy[index] = new Mi("∆"); } } // Scan for functions. // If one is found, increment the number. Because nested // functions which do not contain parentheses (e.g. sin sin x) // are contained in the same row element (in non-Word generated markup), // this allows us to determine how many close parens we need. foreach (IBuildable v in ctxCopy) { if (v is Mi && Semantics.knownFuncts.Contains((v as Mi).Content)) { containsFunct = true; numFuncts++; } } if (containsFunct) { // Only process if this is not the spurious function. if (ctxCopy.Count != 1 || (!Semantics.knownFuncts.Contains((ctxCopy[0] as Mi).Content))) { foreach (IBuildable v in ctxCopy) { v.Visit(sb, context); } for (; numFuncts > 0; numFuncts--) { sb.Append(")"); } } } // No function was found, so process in the normal fashion. else { foreach (var v in ctxCopy) { v.Visit(sb, context); } } }