Skip to content

Commit

Permalink
Add support for \cancel, \bcancel and \xcancel.
Browse files Browse the repository at this point in the history
  • Loading branch information
Orace committed May 22, 2023
1 parent 93ce3c7 commit 620cd87
Show file tree
Hide file tree
Showing 15 changed files with 240 additions and 27 deletions.
11 changes: 0 additions & 11 deletions src/AvaloniaMath/Rendering/AvaloniaBrush.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using Avalonia.Media;
using XamlMath.Colors;
using XamlMath.Rendering;
Expand All @@ -18,16 +17,6 @@ public static AvaloniaBrush FromColor(RgbaColor value) =>
Color.FromArgb(value.A, value.R, value.G, value.B)));
}

public static class AvaloniaBrushExtensions
{
public static Avalonia.Media.IBrush? ToAvalonia(this IBrush? brush) =>
((AvaloniaBrush?)brush)?.Value;

[return: NotNullIfNotNull(nameof(brush))]
public static IBrush? ToPlatform(this Brush? brush) =>
brush == null ? null : AvaloniaBrush.FromBrush(brush);
}

public class AvaloniaBrushFactory : IBrushFactory
{
private AvaloniaBrushFactory() { }
Expand Down
9 changes: 9 additions & 0 deletions src/AvaloniaMath/Rendering/AvaloniaElementRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using XamlMath.Rendering;
using XamlMath.Rendering.Transformations;
using IBrush = XamlMath.Rendering.IBrush;
using Point = XamlMath.Rendering.Point;

namespace AvaloniaMath.Rendering;

Expand All @@ -32,6 +33,14 @@ public void RenderElement(Box box, double x, double y)
box.RenderTo(this, x, y);
}

public void RenderLine(Point point0, Point point1, IBrush? foreground)
{
point0 = GeometryHelper.ScalePoint(_scale, point0);
point1 = GeometryHelper.ScalePoint(_scale, point1);
var pen = new Pen(foreground.ToAvalonia() ?? DefaultForegroundBrush);
_foregroundContext.DrawLine(pen, point0.ToAvalonia(), point1.ToAvalonia());
}

public void RenderCharacter(CharInfo info, double x, double y, IBrush? foreground)
{
var glyph = info.GetGlyphRun(x, y, _scale);
Expand Down
18 changes: 18 additions & 0 deletions src/AvaloniaMath/Rendering/AvaloniaExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Diagnostics.CodeAnalysis;
using Avalonia.Media;
using XamlMath.Rendering;
using IBrush = XamlMath.Rendering.IBrush;

namespace AvaloniaMath.Rendering
{
public static class AvaloniaExtensions
{
[return: NotNullIfNotNull(nameof(brush))]
public static IBrush? ToPlatform(this Brush? brush) => brush == null ? null : AvaloniaBrush.FromBrush(brush);

[return: NotNullIfNotNull(nameof(brush))]
public static Avalonia.Media.IBrush? ToAvalonia(this IBrush? brush) => ((AvaloniaBrush?)brush)?.Value;

public static Avalonia.Point ToAvalonia(this Point point) => new(point.X, point.Y);
}
}
8 changes: 8 additions & 0 deletions src/AvaloniaMath/Rendering/GeometryElementRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ public GeometryElementRenderer(GeometryGroup geometry, double scale)

public void RenderElement(Box box, double x, double y) => box.RenderTo(this, x, y);

public void RenderLine(Point point0, Point point1, IBrush? foreground)
{
point0 = GeometryHelper.ScalePoint(_scale, point0);
point1 = GeometryHelper.ScalePoint(_scale, point1);
var lineGeometry = new LineGeometry(point0.ToAvalonia(), point1.ToAvalonia());
_geometry.Children.Add(lineGeometry);
}

public void RenderCharacter(CharInfo info, double x, double y, IBrush? foreground)
{
/*TODO[#357] var glyph = scaledGlyphFactory(_scale);
Expand Down
1 change: 1 addition & 0 deletions src/WpfMath.Example/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public MainViewModel()
new ("Integral 3", @"L = \int_a^\infty \sqrt[4]{ \left\vert \sum_{i,j=1}^ng_{ij}\left\(\gamma(t)\right\) \left\[\frac{d}{dt}x^i\circ\gamma(t) \right\] \left\{\frac{d}{dt}x^j\circ\gamma(t) \right\} \right\|} \, dt"),
new ("Number matrix", @"\matrix{4&78&3 \\ 5 & 9 & 82 }"),
new ("Nested matrix", @"\matrix{4&78&3\\ 57 & {\matrix{78 \\ 12}} & 20782 }"),
new ("Cancel",@"\cancel{Q} \\ \xcancel{69} \\ \frac{a\bcancel{b}}{\bcancel{b}}"),
new ("Cases", @"f(x) = \cases{1/3 & \mathrm{if} \thinspace 0\le x\le 1;\cr 2/3 & \mathrm{if} \thinspace 3\le x \le 4; \cr 0 & \mathrm{elsewhere.}\cr}"),
new ("Matrix and new lines", @"v \times w = \left( \matrix{v_2 w_3 - v_3 w_2 \\ v_3 w_1 - v_1 w_3 \\ v_1 w_2 - v_2 w_1} \right) \\ \matrix{\mathrm{where} & v= \left(\matrix{ v_1 \\ v_2 \\ v_3 }\right), \\ & w= \left( \matrix{w_1 \\ w_2 \\ w_3} \right)}"),
new ("Big matrix", @"\Gamma_{\mu \rho} ^{\sigma}= \pmatrix{\pmatrix{0 & 0 & 0 \\ 0 & -r & 0 \\ 0 & 0 & -r \sin^2(\theta)} \\ \pmatrix{0 & \frac{1}{r} & 0 \\ \frac{1}{r} & 0 & 0 \\ 0 & 0 & -\sin(\theta) \cos(\theta)} \\ \pmatrix{0 & 0 & \frac{1}{r} \\ 0 & 0 & \frac{1}{\tan(\theta)} \\ \frac{1}{r} & \frac{1}{\tan(\theta)} & 0 }}"),
Expand Down
16 changes: 16 additions & 0 deletions src/WpfMath/Converters/SVGConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ private void AddGeometry(StringBuilder svgString, GeometryGroup group)
GeometryGroup childGroup = (GeometryGroup)geometry;
AddGeometry(svgString, childGroup);
}
else if (geometry is LineGeometry)
{
LineGeometry lineGeometry = (LineGeometry)geometry;
AddGeometry(svgString, lineGeometry);
}
else if (geometry is PathGeometry)
{
PathGeometry path = (PathGeometry)geometry;
Expand All @@ -62,6 +67,17 @@ private void AddGeometry(StringBuilder svgString, GeometryGroup group)
m_nestedLevel--;
}

private void AddGeometry(StringBuilder svgString, LineGeometry line)
{
var x1 = line.StartPoint.X.ToString(CultureInfo.InvariantCulture);
var y1 = line.StartPoint.Y.ToString(CultureInfo.InvariantCulture);

var x2 = line.EndPoint.X.ToString(CultureInfo.InvariantCulture);
var y2 = line.EndPoint.Y.ToString(CultureInfo.InvariantCulture);

svgString.AppendLine(@$"<line x1=""{x1}"" y1=""{y1}"" x2=""{x2}"" y2=""{y2}"" style=""stroke:black;stroke-width:1"" />");
}

private void AddGeometry(StringBuilder svgString, PathGeometry path)
{
svgString.Append("<path d=\"");
Expand Down
7 changes: 7 additions & 0 deletions src/WpfMath/Rendering/GeometryElementRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ public GeometryElementRenderer(GeometryGroup geometry, double scale)
}

public void RenderElement(Box box, double x, double y) => box.RenderTo(this, x, y);
public void RenderLine(Point point0, Point point1, IBrush? foreground)
{
point0 = GeometryHelper.ScalePoint(_scale, point0);
point1 = GeometryHelper.ScalePoint(_scale, point1);
var lineGeometry = new LineGeometry(point0.ToWpf(), point1.ToWpf());
_geometry.Children.Add(lineGeometry);
}

public void RenderCharacter(CharInfo info, double x, double y, IBrush? foreground)
{
Expand Down
18 changes: 11 additions & 7 deletions src/WpfMath/Rendering/WpfElementRenderer.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using WpfMath.Fonts;
using XamlMath;
using XamlMath.Boxes;
using XamlMath.Rendering;
using XamlMath.Rendering.Transformations;
using WpfRect = System.Windows.Rect;

namespace WpfMath.Rendering
{
Expand Down Expand Up @@ -48,6 +48,14 @@ public void RenderElement(Box box, double x, double y)
_foregroundContext.Pop();
}

public void RenderLine(Point point0, Point point1, IBrush? foreground)
{
point0 = GeometryHelper.ScalePoint(_scale, point0);
point1 = GeometryHelper.ScalePoint(_scale, point1);
var pen = new Pen(foreground.ToWpf() ?? DefaultForegroundBrush, 1.0);
_foregroundContext.DrawLine(pen, point0.ToWpf(), point1.ToWpf());
}

public void RenderCharacter(CharInfo info, double x, double y, IBrush? foreground)
{
var glyphRun = info.GetGlyphRun(x, y, _scale);
Expand Down Expand Up @@ -89,12 +97,8 @@ private void RenderBackground(Box box, double x, double y)
{
if (box.Background != null)
{
_targetContext.DrawRectangle(
box.Background.ToWpf(),
null,
new Rect(_scale * x, _scale * (y - box.Height),
_scale * box.TotalWidth,
_scale * box.TotalHeight));
var rectangle = new WpfRect(_scale * x, _scale * (y - box.Height), _scale * box.TotalWidth, _scale * box.TotalHeight);
_targetContext.DrawRectangle(box.Background.ToWpf(), null, rectangle);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
using System.Diagnostics.CodeAnalysis;
using System.Windows.Media;
using XamlMath.Rendering;
using WpfPoint = System.Windows.Point;

namespace WpfMath.Rendering;

public static class WpfBrushExtensions
public static class WpfExtensions
{
public static Brush? ToWpf(this IBrush? brush) => ((WpfBrush?)brush)?.Value;
[return: NotNullIfNotNull(nameof(brush))]
public static IBrush? ToPlatform(this Brush? brush) => brush == null ? null : WpfBrush.FromBrush(brush);

[return: NotNullIfNotNull(nameof(brush))]
public static Brush? ToWpf(this IBrush? brush) => ((WpfBrush?)brush)?.Value;

public static WpfPoint ToWpf(this Point point) => new(point.X, point.Y);
}
33 changes: 33 additions & 0 deletions src/XamlMath.Shared/Atoms/CancelAtom.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using XamlMath.Boxes;

namespace XamlMath.Atoms
{
internal record CancelAtom : Atom
{
private readonly Atom? _contentAtom;
private readonly StrokeBoxMode _strokeBoxMode;

public CancelAtom(SourceSpan atomSource, Atom? contentAtom, StrokeBoxMode strokeBoxMode) : base(atomSource)
{
_contentAtom = contentAtom;
_strokeBoxMode = strokeBoxMode;
}

protected override Box CreateBoxCore(TexEnvironment environment)
{
var contentBox = _contentAtom is null ? StrutBox.Empty : _contentAtom.CreateBox(environment);
var lineBox = new StrokeBox(_strokeBoxMode)
{
Height = contentBox.Height,
Depth = contentBox.Depth,
Width = contentBox.Width
};

var box = new ZBox();
box.Add(contentBox);
box.Add(lineBox);

return box;
}
}
}
44 changes: 44 additions & 0 deletions src/XamlMath.Shared/Boxes/StrokeBox.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using XamlMath.Rendering;

namespace XamlMath.Boxes;

public class StrokeBox : Box
{
private readonly StrokeBoxMode _mode;

public StrokeBox(StrokeBoxMode mode)
{
_mode = mode;
}

public override void RenderTo(IElementRenderer renderer, double x, double y)
{
if (_mode.HasFlag(StrokeBoxMode.Normal))
renderer.RenderLine(new Point(x, y + Depth), new Point(x + Width, y - Height), Foreground);

if (_mode.HasFlag(StrokeBoxMode.Back))
renderer.RenderLine(new Point(x, y - Height), new Point(x + Width, y + Depth), Foreground);
}

public override int GetLastFontId()
{
var fontId = TexFontUtilities.NoFontId;
foreach (var child in Children)
{
fontId = child.GetLastFontId();
if (fontId == TexFontUtilities.NoFontId)
break;
}
return fontId;
}
}

[Flags]
public enum StrokeBoxMode
{
None = 0,
Normal = 1,
Back = 2,
Both = 3
}
38 changes: 38 additions & 0 deletions src/XamlMath.Shared/Boxes/ZBox.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Linq;
using XamlMath.Rendering;

namespace XamlMath.Boxes
{
public class ZBox : Box
{
public override void Add(Box box)
{
base.Add(box);

Width = Children.Select(c => c.Width).DefaultIfEmpty(0).Max();
Height = Children.Select(c => c.Height - c.Shift).DefaultIfEmpty(double.NegativeInfinity).Max();
Depth = Children.Select(c => c.Depth + c.Shift).DefaultIfEmpty(double.NegativeInfinity).Max(); ;
Italic = Children.Select(c => c.Italic).DefaultIfEmpty(double.NegativeInfinity).Max(); ;
}

public override void RenderTo(IElementRenderer renderer, double x, double y)
{
foreach (var box in Children)
{
renderer.RenderElement(box, x, y + box.Shift);
}
}

public override int GetLastFontId()
{
var fontId = TexFontUtilities.NoFontId;
foreach (var child in Children)
{
fontId = child.GetLastFontId();
if (fontId == TexFontUtilities.NoFontId)
break;
}
return fontId;
}
}
}
33 changes: 33 additions & 0 deletions src/XamlMath.Shared/Parsers/StandardCommands.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using XamlMath.Atoms;
using XamlMath.Boxes;
using XamlMath.Parsers.Matrices;

namespace XamlMath.Parsers
Expand Down Expand Up @@ -50,6 +51,35 @@ public CommandProcessingResult ProcessCommand(CommandContext context)
}
}

private class CancelCommand : ICommandParser
{
public static CancelCommand BCancel { get; } = new(StrokeBoxMode.Back);
public static CancelCommand Cancel { get; } = new(StrokeBoxMode.Normal);
public static CancelCommand XCancel { get; } = new(StrokeBoxMode.Both);

private CancelCommand(StrokeBoxMode strokeBoxMode)
{
_strokeBoxMode = strokeBoxMode;
}

private readonly StrokeBoxMode _strokeBoxMode;

public CommandProcessingResult ProcessCommand(CommandContext context)
{
var source = context.CommandSource;
var position = context.ArgumentsStartPosition;
var contentFormula = context.Parser.Parse(TexFormulaParser.ReadElement(source, ref position),
context.Formula.TextStyle,
context.Environment.CreateChildEnvironment());

var start = context.CommandNameStartPosition;
var atomSource = source.Segment(start, position - start);
var cancelAtom = new CancelAtom(atomSource, contentFormula.RootAtom, _strokeBoxMode);

return new CommandProcessingResult(cancelAtom, position);
}
}

/// <summary>
/// This command will parse the remaining part of an input string, and add it onto a new line of a formula. The
/// new line is created as a <see cref="MatrixAtom"/>; the command will try to reuse existing atoms if possible.
Expand Down Expand Up @@ -100,6 +130,9 @@ public CommandProcessingResult ProcessCommand(CommandContext context)
{
[@"\"] = new NewLineCommand(),
["binom"] = new BinomCommand(),
["cancel"] = CancelCommand.Cancel,
["bcancel"] = CancelCommand.BCancel,
["xcancel"] = CancelCommand.XCancel,
["cases"] = MatrixCommandParser.Cases,
["matrix"] = MatrixCommandParser.Matrix,
["pmatrix"] = MatrixCommandParser.PMatrix,
Expand Down
4 changes: 2 additions & 2 deletions src/XamlMath.Shared/Rendering/GeometryHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ namespace XamlMath.Rendering
{
internal static class GeometryHelper
{
public static Rectangle ScaleRectangle(double scale, Rectangle rectangle) =>
new(rectangle.X * scale, rectangle.Y * scale, rectangle.Width * scale, rectangle.Height * scale);
public static Point ScalePoint(double scale, Point point) => new(point.X * scale, point.Y * scale);
public static Rectangle ScaleRectangle(double scale, Rectangle rectangle) => new(rectangle.X * scale, rectangle.Y * scale, rectangle.Width * scale, rectangle.Height * scale);
}
}
Loading

0 comments on commit 620cd87

Please sign in to comment.