diff --git a/src/Formplot/FileFormat/FormplotConverter.cs b/src/Formplot/FileFormat/FormplotConverter.cs index e8bd12d..80d6767 100644 --- a/src/Formplot/FileFormat/FormplotConverter.cs +++ b/src/Formplot/FileFormat/FormplotConverter.cs @@ -92,7 +92,12 @@ public static bool TryConvert( Formplot source, out TPlot? target ) { return source switch { - CurveDistancePlot curve => ConvertToCurveProfile( curve ), + BorePatternPlot typed => ConvertToCurveProfile( typed ), + CurveDistancePlot typed => ConvertToCurveProfile( typed ), + CylindricityPlot typed => ConvertToCurveProfile( typed ), + StraightnessPlot typed => ConvertToCurveProfile( typed ), + RoundnessPlot typed => ConvertToCurveProfile( typed ), + FlatnessPlot typed => ConvertToCurveProfile( typed ), _ => null }; } @@ -120,13 +125,14 @@ private static void CopyDefaults( Formplot source, Formplot target ) private static void CopyDefaults( Point source, Point target ) { - target.Properties.Set( source.Properties ); - target.Tolerance = source.Tolerance; + if( source.HasProperties ) + target.Properties.Set( source.Properties ); + if( source.HasTolerance ) + target.Tolerance = source.Tolerance; target.State = source.State; target.Index = source.Index; } - private static double AdjustAngle( double angle ) { var factor = (int)( angle / 360 ); @@ -315,6 +321,160 @@ private static RoundnessPlot ConvertToRoundness( CylindricityPlot source ) return result; } + private static CurveProfilePlot ConvertToCurveProfile( BorePatternPlot source ) + { + var result = new CurveProfilePlot(); + + CopyDefaults( source, result ); + + result.Actual.CoordinateSystem = source.Actual.CoordinateSystem; + result.Nominal.CoordinateSystem = source.Nominal.CoordinateSystem; + + //Segments and points have a reference to the plot, so we must copy them, despite being of the same type. + foreach( var segment in source.Segments ) + { + var resultSegment = new Segment( segment.Name, segment.SegmentType ); + + foreach( var point in segment.Points ) + { + var resultPoint = new CurvePoint( point.Position, point.Direction, point.Deviation ); + CopyDefaults( point, resultPoint ); + resultSegment.Points.Add( resultPoint ); + } + + result.Segments.Add( resultSegment ); + } + + return result; + } + + private static CurveProfilePlot ConvertToCurveProfile( CylindricityPlot source ) + { + var result = new CurveProfilePlot(); + + CopyDefaults( source, result ); + + result.Actual.CoordinateSystem = source.Actual.CoordinateSystem; + result.Nominal.CoordinateSystem = source.Nominal.CoordinateSystem; + + foreach( var segment in source.Segments ) + { + var resultSegment = new Segment( segment.Name, segment.SegmentType ); + foreach( var point in segment.Points ) + { + var x = Math.Cos( point.Angle ) * source.Nominal.Radius; + var y = Math.Sin( point.Angle ) * source.Nominal.Radius; + + var curvePoint = new CurvePoint( + new Vector( x, y, point.Height * source.Nominal.Height ), + new Vector( x, y ).Normalized(), + point.Deviation ); + + CopyDefaults( point, curvePoint ); + + resultSegment.Points.Add( curvePoint ); + } + + result.Segments.Add( resultSegment ); + } + + return result; + } + + private static CurveProfilePlot ConvertToCurveProfile( StraightnessPlot source ) + { + var result = new CurveProfilePlot(); + + CopyDefaults( source, result ); + + result.Actual.CoordinateSystem = source.Actual.CoordinateSystem; + result.Nominal.CoordinateSystem = source.Nominal.CoordinateSystem; + + foreach( var segment in source.Segments ) + { + var resultSegment = new Segment( segment.Name, segment.SegmentType ); + foreach( var point in segment.Points ) + { + var curvePoint = new CurvePoint( + source.Nominal.Position + ( source.Nominal.Direction * point.Position * source.Nominal.Length ), + source.Nominal.Deviation, + point.Deviation ); + + CopyDefaults( point, curvePoint ); + + resultSegment.Points.Add( curvePoint ); + } + + result.Segments.Add( resultSegment ); + } + + return result; + } + + private static CurveProfilePlot ConvertToCurveProfile( RoundnessPlot source ) + { + var result = new CurveProfilePlot(); + + CopyDefaults( source, result ); + + result.Actual.CoordinateSystem = source.Actual.CoordinateSystem; + result.Nominal.CoordinateSystem = source.Nominal.CoordinateSystem; + + foreach( var segment in source.Segments ) + { + var resultSegment = new Segment( segment.Name, segment.SegmentType ); + foreach( var point in segment.Points ) + { + var x = Math.Cos( point.Angle ) * source.Nominal.Radius; + var y = Math.Sin( point.Angle ) * source.Nominal.Radius; + + var curvePoint = new CurvePoint( + new Vector( x, y ), + new Vector( x, y ).Normalized(), + point.Deviation ); + + CopyDefaults( point, curvePoint ); + + resultSegment.Points.Add( curvePoint ); + } + + result.Segments.Add( resultSegment ); + } + + return result; + } + + private static CurveProfilePlot ConvertToCurveProfile( FlatnessPlot source ) + { + var result = new CurveProfilePlot(); + + CopyDefaults( source, result ); + + result.Actual.CoordinateSystem = source.Actual.CoordinateSystem; + result.Nominal.CoordinateSystem = source.Nominal.CoordinateSystem; + + + foreach( var segment in source.Segments ) + { + var resultSegment = new Segment( segment.Name, segment.SegmentType ); + foreach( var point in segment.Points ) + { + var curvePoint = new CurvePoint( + new Vector( point.Coordinate1 * source.Nominal.Length1, point.Coordinate2 * source.Nominal.Length2 ), + new Vector( 0, 0, 1 ), + point.Deviation ); + + CopyDefaults( point, curvePoint ); + + resultSegment.Points.Add( curvePoint ); + } + + result.Segments.Add( resultSegment ); + } + + return result; + } + private static CurveProfilePlot ConvertToCurveProfile( CurveDistancePlot source ) { var result = new CurveProfilePlot(); diff --git a/src/Formplot/FileFormat/Point.cs b/src/Formplot/FileFormat/Point.cs index a713a64..9aae2c4 100644 --- a/src/Formplot/FileFormat/Point.cs +++ b/src/Formplot/FileFormat/Point.cs @@ -61,6 +61,11 @@ public PropertyCollection Properties set => _Properties = value; } + /// + /// Returns true if this point has a tolerance and the tolerance is not empty. + /// + public bool HasProperties => _Properties is { Count: > 0 }; + /// /// Gets the current state. /// diff --git a/src/Formplot/FileFormat/Segment.cs b/src/Formplot/FileFormat/Segment.cs index 30eb983..2a68c56 100644 --- a/src/Formplot/FileFormat/Segment.cs +++ b/src/Formplot/FileFormat/Segment.cs @@ -29,7 +29,7 @@ public sealed class Segment : Segment, IEquatableConstructor. /// The name. /// Type of the segment. - public Segment( string name, SegmentTypes segmentType ) : base( name, segmentType ) + public Segment( string name = "", SegmentTypes segmentType = SegmentTypes.None ) : base( name, segmentType ) { Points = new PointCollection( this ); } diff --git a/src/Formplot/FileFormat/Vector.cs b/src/Formplot/FileFormat/Vector.cs index e0feb6a..ab85989 100644 --- a/src/Formplot/FileFormat/Vector.cs +++ b/src/Formplot/FileFormat/Vector.cs @@ -95,6 +95,17 @@ internal static Vector Deserialize( XmlReader reader ) return new Vector( x, y, z ); } + /// + /// Returns the vector with normalized length. + /// + public Vector Normalized() + { + var l = Math.Sqrt( X * X + Y * Y + Z * Z ); + return l == 0.0 + ? new Vector( 0 ) + : this / l; + } + public static Vector operator +( Vector a, Vector b ) { return new Vector( a.X + b.X, a.Y + b.Y, a.Z + b.Z ); @@ -105,6 +116,21 @@ internal static Vector Deserialize( XmlReader reader ) return new Vector( a.X - b.X, a.Y - b.Y, a.Z - b.Z ); } + public static Vector operator *( Vector a, double b ) + { + return new Vector( a.X * b, a.Y * b, a.Z * b ); + } + + public static Vector operator *( double b, Vector a ) + { + return a * b; + } + + public static Vector operator /( Vector a, double b ) + { + return new Vector( a.X / b, a.Y / b, a.Z / b ); + } + public static bool operator ==( Vector a, Vector b ) { return Equals( a, b ); diff --git a/src/Tests/FileFormat/FormplotConverterTest.cs b/src/Tests/FileFormat/FormplotConverterTest.cs new file mode 100644 index 0000000..b6b3393 --- /dev/null +++ b/src/Tests/FileFormat/FormplotConverterTest.cs @@ -0,0 +1,215 @@ +#region copyright + +/* * * * * * * * * * * * * * * * * * * * * * * * * */ +/* Carl Zeiss Industrielle Messtechnik GmbH */ +/* Softwaresystem PiWeb */ +/* (c) Carl Zeiss 2025 */ +/* * * * * * * * * * * * * * * * * * * * * * * * * */ + +#endregion + +namespace Zeiss.PiWeb.Formplot.Tests.FileFormat +{ + using System; + using System.Collections.Generic; + using System.Linq; + using NUnit.Framework; + using Zeiss.PiWeb.Formplot.Common; + using Zeiss.PiWeb.Formplot.FileFormat; + + [TestFixture] + [Parallelizable( ParallelScope.All )] + public class FormplotConverterTest + { + [Test] + public void Test_Convert_Straightness_To_Curve() + { + var straightness = new StraightnessPlot + { + Nominal = + { + Position = new Vector( 3, 3, 3 ), + Direction = new Vector( 0, 0, 1 ), + Deviation = new Vector( 0, 1 ), + Length = 2 + } + }; + straightness.Segments.Add( new Segment + { + Points = + { + new LinePoint( 0, 0.1 ), + new LinePoint( 1, 0.2 ) { Tolerance = new Tolerance( 0, 0.3 ) } + } + } ); + + var result = FormplotConverter.TryConvert( straightness, out var curve ); + + Assert.That( result, Is.True ); + Assert.That( curve, Is.Not.Null ); + Assert.That( curve.Points, Has.Exactly( 2 ).Items ); + + var points = curve.Points.ToArray(); + + Assert.That( points[ 0 ].Position, Is.EqualTo( new Vector( 3, 3, 3 ) ) ); + Assert.That( points[ 0 ].Direction, Is.EqualTo( new Vector( 0, 1 ) ) ); + Assert.That( points[ 0 ].Deviation, Is.EqualTo( 0.1 ) ); + Assert.That( points[ 1 ].Position, Is.EqualTo( new Vector( 3, 3, 5 ) ) ); + Assert.That( points[ 1 ].Direction, Is.EqualTo( new Vector( 0, 1 ) ) ); + Assert.That( points[ 1 ].Deviation, Is.EqualTo( 0.2 ) ); + Assert.That( points[ 1 ].Tolerance, Is.EqualTo( new Tolerance( 0, 0.3 ) ) ); + } + + [Test] + public void Test_Convert_Roundness_To_Curve() + { + var roundness = new RoundnessPlot + { + Nominal = + { + Radius = 2 + } + }; + roundness.Segments.Add( new Segment + { + Points = + { + new CirclePoint( 0, 0.1 ), + new CirclePoint( 0.5 * Math.PI, 0.15 ) { Tolerance = new Tolerance( 0, 0.3 ) } + } + } ); + + var result = FormplotConverter.TryConvert( roundness, out var curve ); + + Assert.That( result, Is.True ); + Assert.That( curve, Is.Not.Null ); + Assert.That( curve.Points, Has.Exactly( 2 ).Items ); + + var points = curve.Points.ToArray(); + + Assert.That( points[ 0 ].Position, Is.EqualTo( new Vector( 2 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 0 ].Direction, Is.EqualTo( new Vector( 1 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 0 ].Deviation, Is.EqualTo( 0.1 ) ); + Assert.That( points[ 1 ].Position, Is.EqualTo( new Vector( 0, 2 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 1 ].Direction, Is.EqualTo( new Vector( 0, 1 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 1 ].Deviation, Is.EqualTo( 0.15 ) ); + Assert.That( points[ 1 ].Tolerance, Is.EqualTo( new Tolerance( 0, 0.3 ) ).Using( VectorComparer.Instance ) ); + } + + [Test] + public void Test_Convert_Cylindricity_To_Curve() + { + var cylindricity = new CylindricityPlot + { + Nominal = + { + Height = 3, + Radius = 2 + } + }; + cylindricity.Segments.Add( new Segment + { + Points = + { + new CylinderPoint( 0, 1, 0.1 ), + new CylinderPoint( 0.5 * Math.PI, 2, 0.15 ) + } + } ); + + var result = FormplotConverter.TryConvert( cylindricity, out var curve ); + + Assert.That( result, Is.True ); + Assert.That( curve, Is.Not.Null ); + Assert.That( curve.Points, Has.Exactly( 2 ).Items ); + + var points = curve.Points.ToArray(); + + Assert.That( points[ 0 ].Position, Is.EqualTo( new Vector( 2, 0, 3 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 0 ].Direction, Is.EqualTo( new Vector( 1 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 0 ].Deviation, Is.EqualTo( 0.1 ) ); + Assert.That( points[ 1 ].Position, Is.EqualTo( new Vector( 0, 2, 6 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 1 ].Direction, Is.EqualTo( new Vector( 0, 1 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 1 ].Deviation, Is.EqualTo( 0.15 ) ); + } + + [Test] + public void Test_Convert_Flatness_To_Curve() + { + var flatness = new FlatnessPlot + { + Nominal = + { + Length1 = 4, + Length2 = 3 + } + }; + flatness.Segments.Add( new Segment + { + Points = + { + new PlanePoint( 0, 0, 0.1 ), + new PlanePoint( 2, 2, 0.15 ) + } + } ); + + var result = FormplotConverter.TryConvert( flatness, out var curve ); + + Assert.That( result, Is.True ); + Assert.That( curve, Is.Not.Null ); + Assert.That( curve.Points, Has.Exactly( 2 ).Items ); + + var points = curve.Points.ToArray(); + + Assert.That( points[ 0 ].Position, Is.EqualTo( new Vector( 0 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 0 ].Direction, Is.EqualTo( new Vector( 0, 0, 1 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 0 ].Deviation, Is.EqualTo( 0.1 ) ); + Assert.That( points[ 1 ].Position, Is.EqualTo( new Vector( 8, 6 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 1 ].Direction, Is.EqualTo( new Vector( 0, 0, 1 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 1 ].Deviation, Is.EqualTo( 0.15 ) ); + } + + [Test] + public void Test_Convert_BorePattern_To_Curve() + { + var borepattern = new BorePatternPlot(); + borepattern.Segments.Add( new Segment + { + Points = + { + new CurvePoint( new Vector( 1, 1, 1 ), new Vector( 2, 2, 2 ), 0.1 ), + new CurvePoint( new Vector( 3, 3, 3 ), new Vector( 4, 4, 4 ), 0.15 ) + } + } ); + + var result = FormplotConverter.TryConvert( borepattern, out var curve ); + + Assert.That( result, Is.True ); + Assert.That( curve, Is.Not.Null ); + Assert.That( curve.Points, Has.Exactly( 2 ).Items ); + + var points = curve.Points.ToArray(); + + Assert.That( points[ 0 ].Position, Is.EqualTo( new Vector( 1, 1, 1 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 0 ].Direction, Is.EqualTo( new Vector( 2, 2, 2 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 0 ].Deviation, Is.EqualTo( 0.1 ) ); + Assert.That( points[ 1 ].Position, Is.EqualTo( new Vector( 3, 3, 3 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 1 ].Direction, Is.EqualTo( new Vector( 4, 4, 4 ) ).Using( VectorComparer.Instance ) ); + Assert.That( points[ 1 ].Deviation, Is.EqualTo( 0.15 ) ); + } + + private class VectorComparer : IEqualityComparer + { + public static readonly VectorComparer Instance = new(); + + public bool Equals( Vector x, Vector y ) + { + return x.X.IsCloseTo( y.X ) && x.Y.IsCloseTo( y.Y ) && x.Z.IsCloseTo( y.Z ); + } + + public int GetHashCode( Vector obj ) + { + return 0; + } + } + } +} \ No newline at end of file