Skip to content

Commit 8521dfd

Browse files
author
LoneWandererProductions
committed
Platform independence & rendering architecture improved
- Introduction of VectorLineJoin enum for platform-independent line connections - Enums and interfaces moved to separate namespaces (LightVector.Enums, LightVector.Interfaces) - Color serialization in GraphicObject changed to hex strings; conversion to brushes now takes place in the renderer - Refactoring of WpfVectorRenderer methods: geometry generation and styling clearly separated - BezierCurveFactory now generates geometry instead of paths, control point calculation for WPF corrected - Comments and XML documentation on transformations and file names standardized - Using directives and header comments adapted to new structure - Architecture modularized: data models platform-neutral, renderer platform-specific
1 parent 0e87b91 commit 8521dfd

21 files changed

Lines changed: 187 additions & 202 deletions

CommonLibraryGuiTests/WpfVectorRendererTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using System.Threading;
1616
using System.Linq;
1717
using LightVector;
18+
using LightVector.Enums;
1819

1920
namespace CommonLibraryGuiTests
2021
{

CommonLibraryTests/LightVectorSaveTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using System.Windows;
1414
using System.Xml.Serialization;
1515
using LightVector;
16+
using LightVector.Enums;
1617
using Microsoft.VisualStudio.TestTools.UnitTesting;
1718

1819
namespace CommonLibraryTests

LightVector/BezierCurve.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* COPYRIGHT: See COPYING in the top level directory
33
* PROJECT: LightVector
4-
* FILE: LightVector/BezierCurve.cs
4+
* FILE: BezierCurve.cs
55
* PURPOSE: Hold the Curve Bezier Object
66
* PROGRAMER: Peter Geinitz (Wayfarer)
77
* SOURCES: https://docs.microsoft.com/de-de/dotnet/api/system.drawing.graphics.drawcurve?view=netframework-4.8
@@ -38,7 +38,7 @@ public sealed class BezierCurve : GraphicObject
3838
/// <summary>
3939
/// Checks if this object supports the given transformation.
4040
/// </summary>
41-
/// <param name="transformation"></param>
41+
/// <param name="transformation">Transform Information.</param>
4242
/// <returns>If specific transformation is supported</returns>
4343
public override bool SupportsTransformation(Transform transformation)
4444
{

LightVector/BezierCurveFactory.cs

Lines changed: 51 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,105 @@
11
/*
22
* COPYRIGHT: See COPYING in the top level directory
33
* PROJECT: LightVector
4-
* FILE: LightVector/BezierCurveFactory.cs
4+
* FILE: BezierCurveFactory.cs
55
* PURPOSE: Generate specific Graphic Output Information
66
* PROGRAMER: Peter Geinitz (Wayfarer)
77
*/
88

99
using System;
1010
using System.Collections.Generic;
11-
using System.Linq;
1211
using System.Numerics;
1312
using System.Windows;
1413
using System.Windows.Media;
15-
using System.Windows.Shapes;
1614

1715
namespace LightVector
1816
{
1917
/// <summary>
20-
/// Factory for generating Bezier curves from vector-based points.
18+
/// Factory for generating Bezier geometries from vector-based points.
19+
/// Converts Cardinal Splines (Tension-based) into Cubic Beziers (Control-point based).
2120
/// </summary>
2221
internal static class BezierCurveFactory
2322
{
2423
/// <summary>
25-
/// Generates a Bezier curve from a list of points with a specified tension.
24+
/// Generates a Bezier geometry from a list of points with a specified tension.
2625
/// </summary>
2726
/// <param name="points">The vector points to define the curve.</param>
28-
/// <param name="tension">The tension factor to adjust the curve's shape.</param>
29-
/// <returns>The generated <see cref="Path" /> representing the Bezier curve.</returns>
30-
internal static Path CreateBezierCurve(List<Vector2> points, double tension)
27+
/// <param name="tension">The tension factor (0.0 to 1.0 usually).</param>
28+
/// <returns>The generated <see cref="Geometry" />.</returns>
29+
internal static Geometry CreateBezierGeometry(List<Vector2> points, double tension)
3130
{
3231
if (points == null || points.Count < 2)
3332
{
34-
throw new ArgumentException("At least two points are required to create a Bezier curve.");
33+
return Geometry.Empty;
3534
}
3635

37-
var resultPoints = GenerateCurvePoints(points, tension);
38-
return BuildBezierPath(resultPoints.ToArray());
39-
}
36+
// 1. Calculate the Cubic Bezier points (Control1, Control2, Endpoint, ...)
37+
var segmentPoints = GenerateBezierPoints(points, tension);
4038

41-
/// <summary>
42-
/// Builds a Bezier path using the calculated points.
43-
/// </summary>
44-
/// <param name="points">The calculated points defining the curve.</param>
45-
/// <returns>The generated <see cref="Path" /> for the Bezier curve.</returns>
46-
private static Path BuildBezierPath(IReadOnlyList<Point> points)
47-
{
48-
var path = new Path();
39+
// 2. Build the Geometry
4940
var pathGeometry = new PathGeometry();
50-
path.Data = pathGeometry;
5141

52-
var pathFigure = new PathFigure { StartPoint = points[0] };
53-
pathGeometry.Figures.Add(pathFigure);
42+
// The first point is the StartPoint of the figure
43+
var startPoint = new Point(points[0].X, points[0].Y);
44+
var pathFigure = new PathFigure { StartPoint = startPoint, IsClosed = false };
5445

55-
var pathSegmentCollection = new PathSegmentCollection();
56-
pathFigure.Segments = pathSegmentCollection;
57-
58-
var pointCollection = new PointCollection();
59-
for (var i = 1; i < points.Count; i++)
46+
// Add the segments (groups of 3 points)
47+
var polyBezierSegment = new PolyBezierSegment
6048
{
61-
pointCollection.Add(points[i]);
62-
}
49+
Points = new PointCollection(segmentPoints)
50+
};
51+
52+
pathFigure.Segments.Add(polyBezierSegment);
53+
pathGeometry.Figures.Add(pathFigure);
6354

64-
var bezierSegment = new PolyBezierSegment { Points = pointCollection };
65-
pathSegmentCollection.Add(bezierSegment);
55+
// Freeze for performance since this geometry won't change after creation
56+
if (pathGeometry.CanFreeze) pathGeometry.Freeze();
6657

67-
return path;
58+
return pathGeometry;
6859
}
6960

7061
/// <summary>
71-
/// Generates the points for the Bezier curve based on the input points and tension.
62+
/// Generates the flattened list of points [C1, C2, End, C1, C2, End...] for WPF.
7263
/// </summary>
73-
/// <param name="points">The input vector points.</param>
74-
/// <param name="tension">The tension factor to modify the curve.</param>
75-
/// <returns>The calculated control points for the curve.</returns>
76-
private static IEnumerable<Point> GenerateCurvePoints(IReadOnlyList<Vector2> points, double tension)
64+
private static IEnumerable<Point> GenerateBezierPoints(IReadOnlyList<Vector2> points, double tension)
7765
{
78-
if (points.Count < 2)
79-
{
80-
return Enumerable.Empty<Point>();
81-
}
82-
66+
// Mathematical constant for smoothing Cardinal Splines
8367
var controlScale = tension / 0.5 * 0.175;
84-
var resultPoints = new List<Point> { new(points[0].X, points[0].Y) };
68+
69+
var resultPoints = new List<Point>();
8570

8671
for (var i = 0; i < points.Count - 1; i++)
8772
{
8873
var ptBefore = points[Math.Max(i - 1, 0)];
89-
var pt = points[i];
74+
var ptCurrent = points[i];
9075
var ptAfter = points[i + 1];
9176
var ptAfter2 = points[Math.Min(i + 2, points.Count - 1)];
9277

93-
var dx = ptAfter.X - ptBefore.X;
94-
var dy = ptAfter.Y - ptBefore.Y;
95-
var p2 = new Point(pt.X + (controlScale * dx), pt.Y + (controlScale * dy));
96-
97-
dx = ptAfter2.X - pt.X;
98-
dy = ptAfter2.Y - pt.Y;
99-
100-
var p3 = new Point(ptAfter.X - (controlScale * dx), ptAfter.Y - (controlScale * dy));
101-
78+
// Calculate Control Point 1 (p2)
79+
// Tangent based on previous and next point
80+
var dx1 = ptAfter.X - ptBefore.X;
81+
var dy1 = ptAfter.Y - ptBefore.Y;
82+
var p2 = new Point(
83+
ptCurrent.X + (controlScale * dx1),
84+
ptCurrent.Y + (controlScale * dy1));
85+
86+
// Calculate Control Point 2 (p3)
87+
// Tangent based on current and next-next point
88+
var dx2 = ptAfter2.X - ptCurrent.X;
89+
var dy2 = ptAfter2.Y - ptCurrent.Y;
90+
var p3 = new Point(
91+
ptAfter.X - (controlScale * dx2),
92+
ptAfter.Y - (controlScale * dy2));
93+
94+
// WPF PolyBezierSegment requires exactly 3 points per segment:
95+
// 1. Control Point 1
96+
// 2. Control Point 2
97+
// 3. End Point
10298
resultPoints.Add(p2);
10399
resultPoints.Add(p3);
100+
resultPoints.Add(new Point(ptAfter.X, ptAfter.Y)); // <-- THIS WAS MISSING
104101
}
105102

106-
// No need to add the last point (p4) since it's already included in the original list of points
107-
resultPoints.Add(new Point(points.Last().X, points.Last().Y));
108-
109103
return resultPoints;
110104
}
111105
}

LightVector/CircleObject.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* COPYRIGHT: See COPYING in the top level directory
33
* PROJECT: LightVector
4-
* FILE: LightVector/CircleObject.cs
4+
* FILE: CircleObject.cs
55
* PURPOSE: Generic circle Object
66
* PROGRAMER: Peter Geinitz (Wayfarer)
77
*/
@@ -32,7 +32,7 @@ public sealed class CircleObject : GraphicObject
3232
/// <summary>
3333
/// Checks if this object supports the given transformation.
3434
/// </summary>
35-
/// <param name="transformation"></param>
35+
/// <param name="transformation">Transform Information.</param>
3636
/// <returns>If specific transformation is supported</returns>
3737
public override bool SupportsTransformation(Transform transformation)
3838
{
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* COPYRIGHT: See COPYING in the top level directory
3-
* PROJECT: LightVector
4-
* FILE: LightVector/GraphicTypes.cs
3+
* PROJECT: LightVector.Enums
4+
* FILE: GraphicTypes.cs
55
* PURPOSE: Types of graphic objects
66
* PROGRAMER: Peter Geinitz (Wayfarer)
77
*/
@@ -10,7 +10,7 @@
1010
// ReSharper disable UnusedType.Global
1111
// ReSharper disable UnusedMember.Global
1212

13-
namespace LightVector
13+
namespace LightVector.Enums
1414
{
1515
/// <summary>
1616
/// Describes the typ of Vector Object
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* COPYRIGHT: See COPYING in the top level directory
3+
* PROJECT: LightVector.Enums
4+
* FILE: VectorLineJoin.cs
5+
* PURPOSE: A platform-agnostic enum. The Renderer maps this to PenLineJoin.Bevel, etc.
6+
* PROGRAMER: Peter Geinitz (Wayfarer)
7+
*/
8+
9+
namespace LightVector.Enums
10+
{
11+
12+
/// <summary>
13+
/// A platform-agnostic enum for line join styles. The Renderer will map this to the appropriate PenLineJoin value.
14+
/// </summary>
15+
public enum VectorLineJoin
16+
{
17+
Bevel,
18+
Miter,
19+
Round
20+
}
21+
}

LightVector/GraphicManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* COPYRIGHT: See COPYING in the top level directory
33
* PROJECT: LightVector
4-
* FILE: LightVector/GraphicManager.cs
4+
* FILE: GraphicManager.cs
55
* PURPOSE: Implementation of our Contract for our Library
66
* PROGRAMER: Peter Geinitz (Wayfarer)
77
*/

LightVector/GraphicObject.cs

Lines changed: 9 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* COPYRIGHT: See COPYING in the top level directory
33
* PROJECT: LightVector
4-
* FILE: LightVector/TranslatedLine.cs
4+
* FILE: TranslatedLine.cs
55
* PURPOSE: Hold the Graphic Objects
66
* PROGRAMER: Peter Geinitz (Wayfarer)
77
* SOURCES: https://docs.microsoft.com/de-de/dotnet/api/system.drawing.graphics.drawcurve?view=netframework-4.8
@@ -12,8 +12,6 @@
1212
// ReSharper disable UnusedMember.Global
1313

1414
using System.Collections.Generic;
15-
using System.Windows.Ink;
16-
using System.Windows.Media;
1715
using System.Xml.Serialization;
1816

1917
namespace LightVector
@@ -29,71 +27,26 @@ public abstract class GraphicObject
2927
{
3028
/// <summary>
3129
/// The fill
30+
/// Default null/transparent
3231
/// </summary>
33-
private SolidColorBrush _fill;
32+
public string Fill { get; set; }
3433

3534
/// <summary>
3635
/// The stroke
3736
/// </summary>
38-
private SolidColorBrush _stroke = Brushes.Black;
37+
public string Stroke { get; set; } = "#FF000000";
3938

4039
/// <summary>
4140
/// Optional
4241
/// </summary>
4342
public int Thickness { get; init; } = 1;
4443

4544
/// <summary>
46-
/// Gets or sets the stroke.
47-
/// Optional
48-
/// </summary>
49-
[XmlIgnore]
50-
public SolidColorBrush Stroke
51-
{
52-
get => _stroke;
53-
set
54-
{
55-
_stroke = value;
56-
if (_stroke?.CanFreeze == true) _stroke.Freeze();
57-
}
58-
}
59-
60-
/// <summary>
61-
/// Workaround for XML serialization of Stroke
62-
/// </summary>
63-
[XmlElement("Stroke")]
64-
public string StrokeColor
65-
{
66-
get => Stroke.Color.ToString();
67-
set => Stroke = new SolidColorBrush((Color)ColorConverter.ConvertFromString(value));
68-
}
69-
70-
/// <summary>
71-
/// Optional
72-
/// If filled we will get filled curves
73-
/// </summary>
74-
[XmlIgnore]
75-
public SolidColorBrush Fill
76-
{
77-
get => _fill;
78-
set
79-
{
80-
_fill = value;
81-
if (_fill?.CanFreeze == true) _fill.Freeze();
82-
}
83-
}
84-
85-
/// <summary>
86-
/// Workaround for XML serialization of Fill
45+
/// Gets or sets the optional attributes.
8746
/// </summary>
88-
[XmlElement("Fill")]
89-
public string FillColor
90-
{
91-
get => Fill?.Color.ToString();
92-
set => Fill = string.IsNullOrEmpty(value)
93-
? null
94-
: new SolidColorBrush((Color)ColorConverter.ConvertFromString(value));
95-
}
96-
47+
/// <value>
48+
/// The optional attributes.
49+
/// </value>
9750
[XmlIgnore] public Dictionary<string, object> OptionalAttributes { get; set; } = new();
9851

9952
/// <summary>
@@ -136,7 +89,7 @@ public List<SerializableAttribute> SerializableAttributes
13689
/// <value>
13790
/// The stroke line join.
13891
/// </value>
139-
public PenLineJoin StrokeLineJoin { get; init; } = PenLineJoin.Bevel;
92+
public VectorLineJoin StrokeLineJoin { get; init; } = VectorLineJoin.Bevel;
14093

14194
/// <summary>
14295
/// Checks if this object supports the given transformation.

0 commit comments

Comments
 (0)