diff --git a/Source/Basic Shapes/SvgCircle.cs b/Source/Basic Shapes/SvgCircle.cs index 0aa978563025d64845ad8d7f3c27960f2390c051..8c37c06fb819fb35c167fbff675407f775705825 100644 --- a/Source/Basic Shapes/SvgCircle.cs +++ b/Source/Basic Shapes/SvgCircle.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Drawing; using System.Drawing.Drawing2D; -using System.Xml; -using System.Web.UI.WebControls; -using System.ComponentModel; namespace Svg { @@ -13,7 +6,7 @@ namespace Svg /// An SVG element to render circles to the document. /// [SvgElement("circle")] - public class SvgCircle : SvgVisualElement + public class SvgCircle : SvgPathBasedElement { private GraphicsPath _path; @@ -75,15 +68,6 @@ namespace Svg } } - /// - /// Gets the bounds of the circle. - /// - /// The rectangular bounds of the circle. - public override RectangleF Bounds - { - get { return this.Path(null).GetBounds(); } - } - /// /// Gets the representing this element. /// diff --git a/Source/Basic Shapes/SvgEllipse.cs b/Source/Basic Shapes/SvgEllipse.cs index 749585234a8411366ba28ffa064fd5c680de7451..443d11377c0c997b08e493b103e0539d4b1c39bc 100644 --- a/Source/Basic Shapes/SvgEllipse.cs +++ b/Source/Basic Shapes/SvgEllipse.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Drawing; using System.Drawing.Drawing2D; -using System.Xml; -using System.ComponentModel; namespace Svg { @@ -12,7 +6,7 @@ namespace Svg /// Represents and SVG ellipse element. /// [SvgElement("ellipse")] - public class SvgEllipse : SvgVisualElement + public class SvgEllipse : SvgPathBasedElement { private SvgUnit _radiusX; private SvgUnit _radiusY; @@ -80,15 +74,6 @@ namespace Svg } } - /// - /// Gets the bounds of the element. - /// - /// The bounds. - public override RectangleF Bounds - { - get { return this.Path(null).GetBounds(); } - } - /// /// Gets the for this element. /// diff --git a/Source/Basic Shapes/SvgLine.cs b/Source/Basic Shapes/SvgLine.cs index 1ece3ee9ce991ca9dc99406a26ae8e8f5230a368..86c37aeee00484b3127f0dcd6f12bfdf0fce5edb 100644 --- a/Source/Basic Shapes/SvgLine.cs +++ b/Source/Basic Shapes/SvgLine.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; -using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using Svg.ExtensionMethods; @@ -12,7 +9,7 @@ namespace Svg /// Represents and SVG line element. /// [SvgElement("line")] - public class SvgLine : SvgVisualElement + public class SvgLine : SvgPathBasedElement { private SvgUnit _startX; private SvgUnit _startY; @@ -186,11 +183,6 @@ namespace Svg return result; } - public override System.Drawing.RectangleF Bounds - { - get { return this.Path(null).GetBounds(); } - } - public override SvgElement DeepCopy() { return DeepCopy(); diff --git a/Source/Basic Shapes/SvgPathBasedElement.cs b/Source/Basic Shapes/SvgPathBasedElement.cs new file mode 100644 index 0000000000000000000000000000000000000000..a1f7fcba6d773d0a6dc670547ee6fa59c4c3573f --- /dev/null +++ b/Source/Basic Shapes/SvgPathBasedElement.cs @@ -0,0 +1,24 @@ +using System.Drawing.Drawing2D; + +namespace Svg +{ + /// + /// Represents an element that is using a GraphicsPath as rendering base. + /// + public abstract class SvgPathBasedElement : SvgVisualElement + { + public override System.Drawing.RectangleF Bounds + { + get + { + var path = this.Path(null); + if (Transforms != null && Transforms.Count > 0) + { + path = (GraphicsPath)path.Clone(); + path.Transform(Transforms.GetMatrix()); + } + return path.GetBounds(); + } + } + } +} diff --git a/Source/Basic Shapes/SvgPolygon.cs b/Source/Basic Shapes/SvgPolygon.cs index a2425c220cb46db8197b962a75c186e8f0e0dba6..a1201c924faeeb3f9cbd1a99f5ff965ea19e1b66 100644 --- a/Source/Basic Shapes/SvgPolygon.cs +++ b/Source/Basic Shapes/SvgPolygon.cs @@ -1,11 +1,7 @@ using System; -using System.Collections.Generic; -using System.Text; -using System.Drawing; using System.Drawing.Drawing2D; using System.Diagnostics; using Svg.ExtensionMethods; -using Svg.Pathing; namespace Svg { @@ -13,7 +9,7 @@ namespace Svg /// SvgPolygon defines a closed shape consisting of a set of connected straight line segments. /// [SvgElement("polygon")] - public class SvgPolygon : SvgVisualElement + public class SvgPolygon : SvgPathBasedElement { private GraphicsPath _path; @@ -136,12 +132,6 @@ namespace Svg return result; } - public override RectangleF Bounds - { - get { return this.Path(null).GetBounds(); } - } - - public override SvgElement DeepCopy() { return DeepCopy(); diff --git a/Source/Basic Shapes/SvgRectangle.cs b/Source/Basic Shapes/SvgRectangle.cs index 733272894cfb8a8847abc3c4dc80fcc3ea16a7a4..c2c894e1ecb2c55244fc8bb70442a48769b12866 100644 --- a/Source/Basic Shapes/SvgRectangle.cs +++ b/Source/Basic Shapes/SvgRectangle.cs @@ -1,7 +1,6 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; -using Svg.Transforms; namespace Svg { @@ -9,7 +8,7 @@ namespace Svg /// Represents an SVG rectangle that could also have rounded edges. /// [SvgElement("rect")] - public class SvgRectangle : SvgVisualElement + public class SvgRectangle : SvgPathBasedElement { private SvgUnit _cornerRadiusX; private SvgUnit _cornerRadiusY; @@ -168,15 +167,6 @@ namespace Svg } } - /// - /// Gets the bounds of the element. - /// - /// The bounds. - public override RectangleF Bounds - { - get { return Path(null).GetBounds(); } - } - /// /// Gets the for this element. /// diff --git a/Source/Svg.csproj b/Source/Svg.csproj index c95eaedc327e2bc36476e2f9d1144e17d4e5138b..412c9bc2712e3be1de01ec317a9e8ee26951e5c3 100644 --- a/Source/Svg.csproj +++ b/Source/Svg.csproj @@ -89,6 +89,7 @@ + diff --git a/Source/Text/SvgGlyph.cs b/Source/Text/SvgGlyph.cs index 2517aba0b1d6af930697eb61da5893f43f9ddcc9..9245e9583b5631186456e6896c33f62d9b035903 100644 --- a/Source/Text/SvgGlyph.cs +++ b/Source/Text/SvgGlyph.cs @@ -1,14 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Linq; using Svg.Pathing; using System.Drawing.Drawing2D; namespace Svg { [SvgElement("glyph")] - public class SvgGlyph : SvgVisualElement + public class SvgGlyph : SvgPathBasedElement { private GraphicsPath _path; @@ -79,15 +76,6 @@ namespace Svg return _path; } - /// - /// Gets the bounds of the element. - /// - /// The bounds. - public override System.Drawing.RectangleF Bounds - { - get { return this.Path(null).GetBounds(); } - } - /// /// Initializes a new instance of the class. /// diff --git a/Tests/Svg.UnitTests/BoundsTests.cs b/Tests/Svg.UnitTests/BoundsTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..0e317b348068cea053a91b4f4a2ec9fc2731e645 --- /dev/null +++ b/Tests/Svg.UnitTests/BoundsTests.cs @@ -0,0 +1,68 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Drawing; + +namespace Svg.UnitTests +{ + /// + /// Test class to test bounds for elements without vs. with transformations + /// (see issue 281). Only some basic elements are tested - this should be sufficient + /// to verify the functionality for all path-based elements. + /// + [TestClass] + public class BoundsTests : SvgTestHelper + { + private const string BoundsTestSvg = "Issue281_Bounds.BoundsTest.svg"; + private static SvgDocument testDocument; + + [TestMethod] + public void TestLineBounds() + { + // x1="10" x2="30" y1="20" y2="40", default line thickness is 1 + AssertEqualBounds("line", 9.5f, 19.5f, 21, 21); + // additional translation(5, 5) + AssertEqualBounds("line-xlate", 14.5f, 24.5f, 21, 21); + // additional rotation(180) and translation(-50, 0) + AssertEqualBounds("line-xform", 19.5f, -40.5f, 21, 21); + } + + [TestMethod] + public void TestRectangleBounds() + { + // x="10" y="30" width="10" height="20" + AssertEqualBounds("rect", 9.5f, 29.5f, 10.5f, 20.5f); + // additional translation(10, 10) + AssertEqualBounds("rect-xlate", 19.5f, 39.5f, 10.5f, 20.5f); + // additional rotation(90) + AssertEqualBounds("rect-rot", -50, 9.5f, 20.5f, 10.5f); + } + + [TestMethod] + public void TestGroupBounds() + { + // all lines from TestLineBounds() + AssertEqualBounds("lines", 9.5f, 29.5f, 10.5f, 20.5f); + // all reactangles from TestRectangleBounds() + AssertEqualBounds("rects", 19.5f, 39.5f, 10.5f, 20.5f); + } + + private void AssertEqualBounds(string elementId, float x, float y, float width, float height) + { + const float Epsilon = 0.01f; + var element = GetElement(elementId); + var elementBounds = element.Bounds; + Assert.AreEqual(x, elementBounds.X, Epsilon); + Assert.AreEqual(y, elementBounds.Y, Epsilon); + Assert.AreEqual(width, elementBounds.Width, Epsilon); + Assert.AreEqual(height, elementBounds.Height, Epsilon); + } + + private SvgVisualElement GetElement(string elementId) + { + if (testDocument == null) + { + testDocument = OpenSvg(GetXMLDocFromResource(GetFullResourceString(BoundsTestSvg))); + } + return testDocument.GetElementById(elementId); + } + } +} diff --git a/Tests/Svg.UnitTests/Resources/Issue281_Bounds/BoundsTest.svg b/Tests/Svg.UnitTests/Resources/Issue281_Bounds/BoundsTest.svg new file mode 100644 index 0000000000000000000000000000000000000000..1676c789f9781b03dfb5a029ca5e964dca4804c7 --- /dev/null +++ b/Tests/Svg.UnitTests/Resources/Issue281_Bounds/BoundsTest.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/Tests/Svg.UnitTests/Svg.UnitTests.csproj b/Tests/Svg.UnitTests/Svg.UnitTests.csproj index 92f8e3349783b4efda069063dae53d3c7e24cd48..5be340478b49bbfdbf85a08fb804a467d849c5f2 100644 --- a/Tests/Svg.UnitTests/Svg.UnitTests.csproj +++ b/Tests/Svg.UnitTests/Svg.UnitTests.csproj @@ -54,6 +54,7 @@ + @@ -95,6 +96,9 @@ + + +