Last active
March 19, 2020 01:50
-
-
Save MaxGuernseyIII/1fdb9c9c691a326aeb5649eae894fbac to your computer and use it in GitHub Desktop.
Using SVG shape specifications
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright © Hexagon Software LLC. All rights reserved. | |
using EscapeTiles.Instrumentation; | |
namespace EscapeTiles.Utilities | |
{ | |
sealed class CombineShapeSpecification : ShapeSpecification | |
{ | |
readonly ShapeSpecification Left; | |
readonly ShapeSpecification Right; | |
public CombineShapeSpecification(ShapeSpecification Left, ShapeSpecification Right) | |
{ | |
this.Left = Left; | |
this.Right = Right; | |
} | |
public void Validate(Rectangle Actual) | |
{ | |
Left.Validate(Actual); | |
Right.Validate(Actual); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright © Hexagon Software LLC. All rights reserved. | |
using EscapeTiles.Instrumentation; | |
using Microsoft.VisualStudio.TestTools.UnitTesting; | |
namespace EscapeTiles.Utilities | |
{ | |
sealed class ContainedByShapeSpecification : ShapeSpecification | |
{ | |
readonly Rectangle MustBeOutside; | |
public ContainedByShapeSpecification(Rectangle MustBeOutside) | |
{ | |
this.MustBeOutside = MustBeOutside; | |
} | |
public void Validate(Rectangle Actual) | |
{ | |
Assert.IsTrue(MustBeOutside.ContainsCompletely(Actual), "Expected {0} to be contained by {1}", Actual, MustBeOutside); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright © Hexagon Software LLC. All rights reserved. | |
using EscapeTiles.Instrumentation; | |
using Microsoft.VisualStudio.TestTools.UnitTesting; | |
namespace EscapeTiles.Utilities | |
{ | |
sealed class ContainsShapeSpecification : ShapeSpecification | |
{ | |
readonly Rectangle MustBeInside; | |
public ContainsShapeSpecification(Rectangle MustBeInside) | |
{ | |
this.MustBeInside = MustBeInside; | |
} | |
public void Validate(Rectangle Actual) | |
{ | |
Assert.IsTrue(Actual.ContainsCompletely(MustBeInside), "Expected {0} to contain {1}", Actual, MustBeInside); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright © Hexagon Software LLC. All rights reserved. | |
using System; | |
using System.IO; | |
using EscapeTiles.Instrumentation; | |
using EscapeTiles.Utilities.Svg; | |
namespace EscapeTiles.Utilities | |
{ | |
sealed class GenerateErrorSpecification : ShapeSpecification | |
{ | |
readonly ShapeSpecification Underlying; | |
readonly ArtifactDestination Artifacts; | |
readonly SvgShape Origin; | |
public GenerateErrorSpecification(ShapeSpecification Underlying, ArtifactDestination Artifacts, SvgShape Origin) | |
{ | |
this.Underlying = Underlying; | |
this.Artifacts = Artifacts; | |
this.Origin = Origin; | |
} | |
public void Validate(Rectangle Actual) | |
{ | |
try | |
{ | |
Underlying.Validate(Actual); | |
} | |
catch | |
{ | |
var PeerInNewDocument = Origin.CloneOwnerDocumentAndFindPeer(); | |
var SvgDocument = PeerInNewDocument.Document; | |
PeerInNewDocument.AddClass("failing-expected"); | |
var NewRect = SvgDocument.AddRect(); | |
NewRect.SetCorners(Actual.TopLeft, Actual.BottomRight); | |
NewRect.AddClass("failing-actual"); | |
Artifacts.CreateArtifact($"failure-{Guid.NewGuid():n}.svg", FullPath => | |
{ | |
using var Writer = File.Create(FullPath); | |
SvgDocument.Document.Save(Writer); | |
}); | |
throw; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright © Hexagon Software LLC. All rights reserved. | |
using EscapeTiles.Instrumentation; | |
namespace EscapeTiles.Utilities | |
{ | |
sealed class NoSpecification : ShapeSpecification | |
{ | |
public void Validate(Rectangle Actual) | |
{ | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright © Hexagon Software LLC. All rights reserved. | |
using EscapeTiles.Instrumentation; | |
using EscapeTiles.Utilities.Svg; | |
namespace EscapeTiles.Utilities | |
{ | |
struct RectangleAssertion | |
{ | |
public SvgShape Origin { get; } | |
public Rectangle Operand { get; } | |
public RectangleAssertion(SvgShape Origin, Rectangle Operand) | |
{ | |
this.Origin = Origin; | |
this.Operand = Operand; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright © Hexagon Software LLC. All rights reserved. | |
using EscapeTiles.Instrumentation; | |
namespace EscapeTiles.Utilities | |
{ | |
sealed class ScaleShapeSpecification : ShapeSpecification | |
{ | |
readonly Vector Scale; | |
readonly ShapeSpecification Underlying; | |
internal ScaleShapeSpecification(ShapeSpecification Underlying, Vector Scale) | |
{ | |
this.Underlying = Underlying; | |
this.Scale = Scale; | |
} | |
public void Validate(Rectangle Actual) | |
{ | |
Underlying.Validate(Actual.ScaleBy(Scale)); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright © Hexagon Software LLC. All rights reserved. | |
using EscapeTiles.Instrumentation; | |
namespace EscapeTiles.Utilities | |
{ | |
public interface ShapeSpecification | |
{ | |
void Validate(Rectangle Actual); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright © Hexagon Software LLC. All rights reserved. | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Text.RegularExpressions; | |
using System.Xml.Linq; | |
using EscapeTiles.Instrumentation; | |
using EscapeTiles.Utilities.Svg; | |
using Microsoft.VisualStudio.TestTools.UnitTesting; | |
namespace EscapeTiles.Utilities | |
{ | |
sealed class ShapeSpecifications | |
{ | |
readonly ArtifactDestination Artifacts; | |
readonly (float BoxWidth, float BoxHeight) Scale; | |
readonly SvgDocument SvgDocument; | |
ShapeSpecifications(XDocument Document, ArtifactDestination Artifacts) | |
{ | |
SvgDocument = new SvgDocument(Document); | |
this.Artifacts = Artifacts; | |
var (X, Y, Width, Height) = SvgDocument.ViewBox; | |
Assert.AreEqual(0, X); | |
Assert.AreEqual(0, Y); | |
Scale = (Width, Height); | |
} | |
internal static Func<Stream, ShapeSpecifications> Reconstitute(ArtifactDestination Artifacts) | |
{ | |
return From => new ShapeSpecifications(XDocument.Load(From), Artifacts); | |
} | |
internal ShapeSpecification GetViewportRequirement(string Key) | |
{ | |
var Rectangles = FindSelectedRectanglesInDocument(Key); | |
var Result = ConvertRectanglesToShapeSpecification(Rectangles); | |
if (Result is NoSpecification) | |
Assert.Fail($"No valid rules found for key '{Key}'"); | |
return ApplyScale(Result); | |
} | |
ShapeSpecification ApplyScale(ShapeSpecification Result) => new ScaleShapeSpecification(Result, Scale); | |
ShapeSpecification ConvertRectanglesToShapeSpecification(IEnumerable<RectangleSpecification> Rectangles) | |
{ | |
ShapeSpecification Result = new NoSpecification(); | |
foreach (var RectangleRule in Rectangles) | |
{ | |
var Next = ConvertRectangleToSpecification(RectangleRule.Origin.Id, RectangleRule.Operand); | |
if (Next == null) | |
continue; | |
Next = new AddContextSpecification( | |
new GenerateErrorSpecification(Next, Artifacts, RectangleRule.Origin), RectangleRule.Origin.Id); | |
Result = new CombineShapeSpecification(Result, Next); | |
} | |
return Result; | |
} | |
IEnumerable<RectangleSpecification> FindSelectedRectanglesInDocument(string Key) | |
{ | |
var SourceRectangles = SvgDocument.Rects.Select(ToRectangleRule) | |
.Concat(SvgDocument.Polygons.Select(ToRectangleRule)) | |
.Concat(SvgDocument.Polylines.Select(ToRectangleRule)); | |
return SourceRectangles.Where(R => Regex.IsMatch(R.Origin.Id, $@"^{Key}(?:\.[^.]*)*$", RegexOptions.IgnoreCase)); | |
} | |
static ShapeSpecification ConvertRectangleToSpecification(string Id, Rectangle ExpectedViewportRectangle) | |
{ | |
Id = Id.Trim(); | |
if (IsOfType("inner")) | |
return new ContainsShapeSpecification(ExpectedViewportRectangle); | |
if (IsOfType("outer")) | |
return new ContainedByShapeSpecification(ExpectedViewportRectangle); | |
return null; | |
bool IsOfType(string Indicator) | |
{ | |
return Regex.IsMatch(Id, $@"^(?:[^.]*\.)*{Indicator}$", RegexOptions.IgnoreCase); | |
} | |
} | |
static RectangleSpecification ToRectangleRule(SvgPolygon Polygon) | |
{ | |
var Points = Polygon.Points; | |
var Min = Points[0]; | |
var Max = Points[2]; | |
return new RectangleSpecification(Polygon, Rectangle.ScreenAligned(Min, Max)); | |
} | |
static RectangleSpecification ToRectangleRule(SvgRect Rect) => | |
new RectangleSpecification(Rect, Rectangle.ScreenAligned(Rect.Min, Rect.Max)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment