From 3711b6ef6b4387d23b46c022723e604660757dd5 Mon Sep 17 00:00:00 2001 From: Mike Smith Date: Sun, 14 Feb 2016 22:53:04 -0800 Subject: [PATCH 01/13] Added Matrix.cs, matrix multiply method, Vector to matrix factory method --- OSCADSharp/OSCADSharp/OSCADSharp.csproj | 1 + OSCADSharp/OSCADSharp/Spatial/Matrix.cs | 164 ++++++++++++++++++++++++ OSCADSharp/OSCADSharp/Vector3.cs | 9 +- 3 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 OSCADSharp/OSCADSharp/Spatial/Matrix.cs diff --git a/OSCADSharp/OSCADSharp/OSCADSharp.csproj b/OSCADSharp/OSCADSharp/OSCADSharp.csproj index edbee13..bcbbaf7 100644 --- a/OSCADSharp/OSCADSharp/OSCADSharp.csproj +++ b/OSCADSharp/OSCADSharp/OSCADSharp.csproj @@ -41,6 +41,7 @@ + diff --git a/OSCADSharp/OSCADSharp/Spatial/Matrix.cs b/OSCADSharp/OSCADSharp/Spatial/Matrix.cs new file mode 100644 index 0000000..9e22dd8 --- /dev/null +++ b/OSCADSharp/OSCADSharp/Spatial/Matrix.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OSCADSharp.Spatial +{ + /// + /// An n-dimensional Matrix for performing operations on doubles that + /// represent spatial positions + /// + internal class Matrix + { + #region Fields/Properties + private double[] values; + + internal int ColumnCount { get; private set; } + internal int RowCount { get; private set; } + + internal double[] GetValues() + { + return this.values; + } + #endregion + + #region Constructors + internal Matrix(double[] values, int numRows, int numColumns) + { + this.values = values; + this.RowCount = numRows; + this.ColumnCount = numColumns; + } + + internal Matrix(List values, int numColumns) + { + this.values = values.ToArray(); + this.ColumnCount = numColumns; + this.RowCount = values.Count / numColumns; + } + #endregion + + #region Public API + internal Matrix Multiply(Matrix other) + { + double[] otherValues = other.GetValues(); + List result = new List(); + int currentRowInResult = 0; + + //Iterate over each row in this matrix + for (int row = 0; row < this.RowCount; row++) + { + //And iterate over each column in the other matrix + for (int column = 0; column < other.ColumnCount; column++) + { + // Multiply item in the current row on the left, by each item in column right + // and add it to the result in the corresponding row/column + for (int leftMatrixColumn = 0; leftMatrixColumn < this.ColumnCount; leftMatrixColumn++) + { + result[currentRowInResult * other.ColumnCount + column] += + this.values[row * this.ColumnCount + leftMatrixColumn] * + otherValues[leftMatrixColumn * other.ColumnCount + column]; + } + } + + currentRowInResult++; + } + + return new Matrix(result, other.ColumnCount); + } + #endregion + + #region Static Transformation Matrices + private static readonly double piOver180 = Math.PI / 180; + private static double toRadians(double degrees) + { + return piOver180 * degrees; + } + + private static readonly Matrix identity = new Matrix(new double[] { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + }, 4, 4); + internal static Matrix Identity { get { return identity; } } + + /// + /// Gets a transformation matrix for performing rotations on the X-Axis + /// (Assuming you are in a right-handed 3D world) + /// + /// Degrees of rotation + /// Transformation matrix to perform the rotation + internal static Matrix XRotation(double angle) + { + double radAngle = toRadians(angle); + double[] rotationArr = new double[] { + 1 , 0, 0, 0, + 0, Math.Cos(radAngle), Math.Sin(radAngle), 0, + 0, -Math.Sin(radAngle), Math.Cos(radAngle), 0, + 0, 0, 0, 1 + }; + + return new Matrix(rotationArr, 4, 4); + } + + /// + /// Gets a transformation matrix for performing rotations on the Y-Axis + /// (Assuming you are in a right-handed 3D world) + /// + /// Degrees of rotation + /// Transformation matrix to perform the rotation + internal static Matrix YRotation(double angle) + { + double radAngle = toRadians(angle); + double[] rotationArr = new double[] { + Math.Cos(radAngle), 0, -Math.Sin(radAngle), 0, + 0, 1, 0, 0, + Math.Sin(radAngle), 0, Math.Cos(radAngle), 0, + 0, 0, 0, 1 + }; + + return new Matrix(rotationArr, 4, 4); + } + + /// + /// Gets a transformation matrix for performing rotations on the Z-Axis + /// (Assuming you are in a right-handed 3D world) + /// + /// Degrees of rotation + /// Transformation matrix to perform the rotation + internal static Matrix ZRotation(double angle) + { + double radAngle = toRadians(angle); + double[] rotationArr = new double[] { + Math.Cos(radAngle), Math.Sin(radAngle), 0, 0, + -Math.Sin(radAngle), Math.Cos(radAngle), 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + }; + + return new Matrix(rotationArr, 4, 4); + } + + /// + /// Gets a point's position after rotations have been applied + /// + /// Point to rotate + /// + /// + /// + /// Point after rotation + internal static Vector3 GetRotatedPoint(Vector3 point, double xAngle, double yAngle, double zAngle) + { + Matrix transformation = XRotation(xAngle) + .Multiply(YRotation(yAngle)) + .Multiply(ZRotation(zAngle)); + + double[] result = transformation.Multiply(point.ToMatrix()).GetValues(); + return new Vector3(result[0], result[1], result[2]); + } + #endregion + } +} diff --git a/OSCADSharp/OSCADSharp/Vector3.cs b/OSCADSharp/OSCADSharp/Vector3.cs index 72a9ae1..22d1192 100644 --- a/OSCADSharp/OSCADSharp/Vector3.cs +++ b/OSCADSharp/OSCADSharp/Vector3.cs @@ -1,4 +1,5 @@ -using System; +using OSCADSharp.Spatial; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -57,6 +58,12 @@ namespace OSCADSharp } #endregion + internal Matrix ToMatrix() + { + double[] coords = { this.X, this.Y, this.Z, 0 }; + return new Matrix(coords, 4, 1); + } + public override string ToString() { return String.Format("[X: {0}, Y: {1}, Z: {2}]", this.X.ToString(), this.Y.ToString(), this.Z.ToString()); From bc69fa877b4a11ecc190a0837f710c0ec34b8af7 Mon Sep 17 00:00:00 2001 From: Mike Smith Date: Sun, 14 Feb 2016 22:53:28 -0800 Subject: [PATCH 02/13] Moved Vector3 to Spatial folder --- OSCADSharp/OSCADSharp/OSCADSharp.csproj | 2 +- OSCADSharp/OSCADSharp/{ => Spatial}/Vector3.cs | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename OSCADSharp/OSCADSharp/{ => Spatial}/Vector3.cs (100%) diff --git a/OSCADSharp/OSCADSharp/OSCADSharp.csproj b/OSCADSharp/OSCADSharp/OSCADSharp.csproj index bcbbaf7..16dc350 100644 --- a/OSCADSharp/OSCADSharp/OSCADSharp.csproj +++ b/OSCADSharp/OSCADSharp/OSCADSharp.csproj @@ -63,7 +63,7 @@ - + diff --git a/OSCADSharp/OSCADSharp/Vector3.cs b/OSCADSharp/OSCADSharp/Spatial/Vector3.cs similarity index 100% rename from OSCADSharp/OSCADSharp/Vector3.cs rename to OSCADSharp/OSCADSharp/Spatial/Vector3.cs From 49d2de30467f54e1eda541120834e9545f5d03c1 Mon Sep 17 00:00:00 2001 From: Mike Smith Date: Sun, 14 Feb 2016 23:00:27 -0800 Subject: [PATCH 03/13] + Added new abstract 'position' method to OSCADObject, overrides on all pertinent classes. (Not implemented yet) --- OSCADSharp/OSCADSharp/OSCADObject.cs | 11 +++++++++++ .../OSCADSharp/Scripting/MultiBlockStatementObject.cs | 5 +++++ OSCADSharp/OSCADSharp/Solids/Cube.cs | 5 +++++ OSCADSharp/OSCADSharp/Solids/Cylinder.cs | 5 +++++ OSCADSharp/OSCADSharp/Solids/Sphere.cs | 5 +++++ OSCADSharp/OSCADSharp/Solids/Text3D.cs | 6 ++++++ OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs | 5 +++++ .../OSCADSharp/Transforms/LinearExtrudedObject.cs | 6 +++++- OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs | 5 +++++ OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs | 5 +++++ OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs | 5 +++++ OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs | 5 +++++ OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs | 5 +++++ 13 files changed, 72 insertions(+), 1 deletion(-) diff --git a/OSCADSharp/OSCADSharp/OSCADObject.cs b/OSCADSharp/OSCADSharp/OSCADObject.cs index d3034a0..9205685 100644 --- a/OSCADSharp/OSCADSharp/OSCADObject.cs +++ b/OSCADSharp/OSCADSharp/OSCADObject.cs @@ -204,6 +204,17 @@ namespace OSCADSharp #endregion #region Utility Methods + protected Vector3 position; + /// + /// Returns the computed position of this object. + /// + /// For some objects that are the aggregate of many operations or + /// multiple children, this may be an approximation or average + /// of the position. + /// + /// + public abstract Vector3 Position(); + /// /// Creates a copy of this object and all of its children /// diff --git a/OSCADSharp/OSCADSharp/Scripting/MultiBlockStatementObject.cs b/OSCADSharp/OSCADSharp/Scripting/MultiBlockStatementObject.cs index 0abf646..4399fcc 100644 --- a/OSCADSharp/OSCADSharp/Scripting/MultiBlockStatementObject.cs +++ b/OSCADSharp/OSCADSharp/Scripting/MultiBlockStatementObject.cs @@ -43,5 +43,10 @@ namespace OSCADSharp.Scripting return new MultiBlockStatementObject(this.outerStatement, childClones); } + + public override Vector3 Position() + { + throw new NotImplementedException(); + } } } diff --git a/OSCADSharp/OSCADSharp/Solids/Cube.cs b/OSCADSharp/OSCADSharp/Solids/Cube.cs index 2264b2c..70f8869 100644 --- a/OSCADSharp/OSCADSharp/Solids/Cube.cs +++ b/OSCADSharp/OSCADSharp/Solids/Cube.cs @@ -76,6 +76,11 @@ namespace OSCADSharp.Solids Center = this.Center }; } + + public override Vector3 Position() + { + throw new NotImplementedException(); + } #endregion } } diff --git a/OSCADSharp/OSCADSharp/Solids/Cylinder.cs b/OSCADSharp/OSCADSharp/Solids/Cylinder.cs index 22f6bbc..cd64f00 100644 --- a/OSCADSharp/OSCADSharp/Solids/Cylinder.cs +++ b/OSCADSharp/OSCADSharp/Solids/Cylinder.cs @@ -137,6 +137,11 @@ namespace OSCADSharp.Solids Center = this.Center }; } + + public override Vector3 Position() + { + throw new NotImplementedException(); + } #endregion } } diff --git a/OSCADSharp/OSCADSharp/Solids/Sphere.cs b/OSCADSharp/OSCADSharp/Solids/Sphere.cs index e3c16c2..c397449 100644 --- a/OSCADSharp/OSCADSharp/Solids/Sphere.cs +++ b/OSCADSharp/OSCADSharp/Solids/Sphere.cs @@ -80,6 +80,11 @@ namespace OSCADSharp.Solids Radius = this.Radius }; } + + public override Vector3 Position() + { + throw new NotImplementedException(); + } #endregion } } diff --git a/OSCADSharp/OSCADSharp/Solids/Text3D.cs b/OSCADSharp/OSCADSharp/Solids/Text3D.cs index 2a69ba0..18fd767 100644 --- a/OSCADSharp/OSCADSharp/Solids/Text3D.cs +++ b/OSCADSharp/OSCADSharp/Solids/Text3D.cs @@ -59,6 +59,7 @@ namespace OSCADSharp.Solids public string Language { get; set; } #endregion + #region Constructors /// /// Creates 3d text with the default parameters @@ -125,6 +126,11 @@ namespace OSCADSharp.Solids var formatter = new SingleBlockFormatter(String.Format("linear_extrude(height = {0})", 1), sb.ToString()); return formatter.ToString(); } + + public override Vector3 Position() + { + throw new NotImplementedException(); + } #endregion } } diff --git a/OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs b/OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs index af988aa..5583e33 100644 --- a/OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs @@ -50,5 +50,10 @@ namespace OSCADSharp.Transforms { return new ColoredObject(obj, this.ColorName, this.Opacity); } + + public override Vector3 Position() + { + throw new NotImplementedException(); + } } } diff --git a/OSCADSharp/OSCADSharp/Transforms/LinearExtrudedObject.cs b/OSCADSharp/OSCADSharp/Transforms/LinearExtrudedObject.cs index a6744e2..25a6a19 100644 --- a/OSCADSharp/OSCADSharp/Transforms/LinearExtrudedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/LinearExtrudedObject.cs @@ -36,7 +36,6 @@ namespace OSCADSharp.Transforms this.children.Add(obj); } - public override OSCADObject Clone() { return new LinearExtrudedObject(this.obj.Clone(), this.Height); @@ -48,5 +47,10 @@ namespace OSCADSharp.Transforms var formatter = new SingleBlockFormatter(extrudeCommand, this.obj.ToString()); return formatter.ToString(); } + + public override Vector3 Position() + { + throw new NotImplementedException(); + } } } diff --git a/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs b/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs index 7d7f22d..7eb1793 100644 --- a/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs @@ -49,5 +49,10 @@ namespace OSCADSharp.Transforms { return new MirroredObject(obj, this.Normal); } + + public override Vector3 Position() + { + throw new NotImplementedException(); + } } } diff --git a/OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs b/OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs index c058ea8..a5bd317 100644 --- a/OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs @@ -48,5 +48,10 @@ namespace OSCADSharp.Transforms { return new ResizedObject(obj, this.Size); } + + public override Vector3 Position() + { + throw new NotImplementedException(); + } } } diff --git a/OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs b/OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs index e21f975..aa7c787 100644 --- a/OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs @@ -48,5 +48,10 @@ namespace OSCADSharp.Transforms { return new RotatedObject(obj, this.Angle); } + + public override Vector3 Position() + { + throw new NotImplementedException(); + } } } diff --git a/OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs b/OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs index aadeade..563d0a4 100644 --- a/OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs @@ -48,5 +48,10 @@ namespace OSCADSharp.Transforms { return new ScaledObject(obj, this.ScaleFactor); } + + public override Vector3 Position() + { + throw new NotImplementedException(); + } } } diff --git a/OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs b/OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs index 636319c..78b3d47 100644 --- a/OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs @@ -45,5 +45,10 @@ namespace OSCADSharp.Transforms { return new TranslatedObject(obj, this.Vector); } + + public override Vector3 Position() + { + throw new NotImplementedException(); + } } } From 2a7ee3ab63ad098239b070ce2557140e01f707d8 Mon Sep 17 00:00:00 2001 From: Mike Smith Date: Sun, 14 Feb 2016 23:27:53 -0800 Subject: [PATCH 04/13] Added Cube position, Translate interpolation --- OSCADSharp/OSCADSharp.ConsoleTests/Program.cs | 12 ++++--- OSCADSharp/OSCADSharp.UnitTests/CubeTests.cs | 32 +++++++++++++++++++ OSCADSharp/OSCADSharp/OSCADObject.cs | 1 - OSCADSharp/OSCADSharp/Solids/Cube.cs | 12 ++++++- OSCADSharp/OSCADSharp/Spatial/Vector3.cs | 26 ++++++++++++++- .../OSCADSharp/Transforms/ColoredObject.cs | 2 +- .../OSCADSharp/Transforms/TranslatedObject.cs | 2 +- 7 files changed, 78 insertions(+), 9 deletions(-) diff --git a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs index 778f730..da9aad6 100644 --- a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs +++ b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs @@ -13,11 +13,15 @@ namespace OSCADSharp.ConsoleTests { static void Main(string[] args) { - var cube = new Cube(); - var sphere = new Sphere().Translate(0, 0, 2); - var hull = cube.Hull(sphere); + var cube = new Cube(50, 50, 50).Translate(10, 10, 0); - string script = hull.ToString(); + var pos = cube.Position(); + var cyl1 = new Cylinder(1, 100, true).Translate(pos); + var cyl2 = new Cylinder(1, 100, true).Rotate(0, 90, 0).Translate(pos); + var cyl3 = new Cylinder(1, 100, true).Rotate(90, 0, 0).Translate(pos); + var axisHelper = cyl1.Union(cyl2, cyl3).Color("Red"); + + string script = cube.Union(axisHelper).ToString(); File.WriteAllLines("test.scad", new string[] { script.ToString() }); //Console.ReadKey(); diff --git a/OSCADSharp/OSCADSharp.UnitTests/CubeTests.cs b/OSCADSharp/OSCADSharp.UnitTests/CubeTests.cs index 9af5d5f..2968f8a 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/CubeTests.cs +++ b/OSCADSharp/OSCADSharp.UnitTests/CubeTests.cs @@ -53,5 +53,37 @@ namespace OSCADSharp.UnitTests Assert.IsTrue(script.StartsWith("cube(")); Assert.IsTrue(script.EndsWith(");")); } + + [TestMethod] + public void Cube_InitialPositionForNonCenteredCubeIsHalfLengthWidthAndHeight() + { + var cube = new Cube(10, 10, 10); + + Assert.IsTrue(cube.Position() == new Vector3(5, 5, 5)); + } + + [TestMethod] + public void Cube_InitialPositionIfCenteredIsOrigin() + { + var cube = new Cube(25, 25, 25, true); + + Assert.AreEqual(new Vector3(), cube.Position()); + } + + [TestMethod] + public void Cube_PositionMovesWithCubeOnTranslate() + { + var cube = new Cube(50, 50, 50).Translate(10, 10, 0); + + Assert.AreEqual(new Vector3(35, 35, 25), cube.Position()); + } + + [TestMethod] + public void Cube_PositionMovesWithCubeOnNegativeTranslate() + { + var cube = new Cube(50, 50, 50, true).Translate(-5, 0, -15); + + Assert.AreEqual(new Vector3(-5, 0, -15), cube.Position()); + } } } diff --git a/OSCADSharp/OSCADSharp/OSCADObject.cs b/OSCADSharp/OSCADSharp/OSCADObject.cs index 9205685..4ee907e 100644 --- a/OSCADSharp/OSCADSharp/OSCADObject.cs +++ b/OSCADSharp/OSCADSharp/OSCADObject.cs @@ -204,7 +204,6 @@ namespace OSCADSharp #endregion #region Utility Methods - protected Vector3 position; /// /// Returns the computed position of this object. /// diff --git a/OSCADSharp/OSCADSharp/Solids/Cube.cs b/OSCADSharp/OSCADSharp/Solids/Cube.cs index 70f8869..6945e1a 100644 --- a/OSCADSharp/OSCADSharp/Solids/Cube.cs +++ b/OSCADSharp/OSCADSharp/Solids/Cube.cs @@ -79,7 +79,17 @@ namespace OSCADSharp.Solids public override Vector3 Position() { - throw new NotImplementedException(); + Vector3 position; + if(this.Center == false) + { + position = new Vector3(this.Size.X / 2, this.Size.Y / 2, this.Size.Z / 2); + } + else + { + position = new Vector3(); + } + + return position; } #endregion } diff --git a/OSCADSharp/OSCADSharp/Spatial/Vector3.cs b/OSCADSharp/OSCADSharp/Spatial/Vector3.cs index 22d1192..dbf858c 100644 --- a/OSCADSharp/OSCADSharp/Spatial/Vector3.cs +++ b/OSCADSharp/OSCADSharp/Spatial/Vector3.cs @@ -46,7 +46,31 @@ namespace OSCADSharp return new Vector3(this.X, this.Y, this.Z); } - #region Operators + #region Operators/Overrides + public override bool Equals(object obj) + { + return this.GetHashCode() == obj.GetHashCode(); + } + + public override int GetHashCode() + { + return this.ToString().GetHashCode(); + } + + public static bool operator ==(Vector3 left, Vector3 right) + { + return left.X == right.X && + left.Y == right.Y && + left.Z == right.Z; + } + + public static bool operator !=(Vector3 left, Vector3 right) + { + return !(left.X == right.X && + left.Y == right.Y && + left.Z == right.Z); + } + public static Vector3 operator +(Vector3 left, Vector3 right) { return new Vector3(left.X + right.X, left.Y + right.Y, left.Z + right.Z); diff --git a/OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs b/OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs index 5583e33..6c6a047 100644 --- a/OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs @@ -53,7 +53,7 @@ namespace OSCADSharp.Transforms public override Vector3 Position() { - throw new NotImplementedException(); + return this.obj.Position(); } } } diff --git a/OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs b/OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs index 78b3d47..e9f0c81 100644 --- a/OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs @@ -48,7 +48,7 @@ namespace OSCADSharp.Transforms public override Vector3 Position() { - throw new NotImplementedException(); + return this.obj.Position() + this.Vector; } } } From 1be343fadc272a7083b6c33e5b13d5e6e3275d33 Mon Sep 17 00:00:00 2001 From: Mike Smith Date: Mon, 15 Feb 2016 00:31:20 -0800 Subject: [PATCH 05/13] Possible functioning implementation of Rotate's point interpolation (at least with center=true). Further testing needed. --- OSCADSharp/OSCADSharp.ConsoleTests/Program.cs | 2 +- OSCADSharp/OSCADSharp/Spatial/Matrix.cs | 20 +++++++++++++------ .../OSCADSharp/Transforms/RotatedObject.cs | 3 ++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs index da9aad6..535df3f 100644 --- a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs +++ b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs @@ -13,7 +13,7 @@ namespace OSCADSharp.ConsoleTests { static void Main(string[] args) { - var cube = new Cube(50, 50, 50).Translate(10, 10, 0); + var cube = new Cube(50, 50, 50, true).Translate(30, 30, 30).Rotate(25, 45, -90); var pos = cube.Position(); var cyl1 = new Cylinder(1, 100, true).Translate(pos); diff --git a/OSCADSharp/OSCADSharp/Spatial/Matrix.cs b/OSCADSharp/OSCADSharp/Spatial/Matrix.cs index 9e22dd8..981acd8 100644 --- a/OSCADSharp/OSCADSharp/Spatial/Matrix.cs +++ b/OSCADSharp/OSCADSharp/Spatial/Matrix.cs @@ -57,6 +57,7 @@ namespace OSCADSharp.Spatial // and add it to the result in the corresponding row/column for (int leftMatrixColumn = 0; leftMatrixColumn < this.ColumnCount; leftMatrixColumn++) { + result.Add(0); result[currentRowInResult * other.ColumnCount + column] += this.values[row * this.ColumnCount + leftMatrixColumn] * otherValues[leftMatrixColumn * other.ColumnCount + column]; @@ -93,6 +94,9 @@ namespace OSCADSharp.Spatial /// Transformation matrix to perform the rotation internal static Matrix XRotation(double angle) { + if (angle == 0) + return Identity; + double radAngle = toRadians(angle); double[] rotationArr = new double[] { 1 , 0, 0, 0, @@ -112,6 +116,9 @@ namespace OSCADSharp.Spatial /// Transformation matrix to perform the rotation internal static Matrix YRotation(double angle) { + if (angle == 0) + return Identity; + double radAngle = toRadians(angle); double[] rotationArr = new double[] { Math.Cos(radAngle), 0, -Math.Sin(radAngle), 0, @@ -131,6 +138,9 @@ namespace OSCADSharp.Spatial /// Transformation matrix to perform the rotation internal static Matrix ZRotation(double angle) { + if (angle == 0) + return Identity; + double radAngle = toRadians(angle); double[] rotationArr = new double[] { Math.Cos(radAngle), Math.Sin(radAngle), 0, 0, @@ -152,12 +162,10 @@ namespace OSCADSharp.Spatial /// Point after rotation internal static Vector3 GetRotatedPoint(Vector3 point, double xAngle, double yAngle, double zAngle) { - Matrix transformation = XRotation(xAngle) - .Multiply(YRotation(yAngle)) - .Multiply(ZRotation(zAngle)); - - double[] result = transformation.Multiply(point.ToMatrix()).GetValues(); - return new Vector3(result[0], result[1], result[2]); + var x = XRotation(-xAngle).Multiply(point.ToMatrix()); + var y = YRotation(-yAngle).Multiply(x); + var z = ZRotation(-zAngle).Multiply(y).GetValues(); + return new Vector3(z[0], z[1], z[2]); } #endregion } diff --git a/OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs b/OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs index aa7c787..c83aa95 100644 --- a/OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs @@ -1,4 +1,5 @@ using OSCADSharp.Scripting; +using OSCADSharp.Spatial; using System; using System.Collections.Generic; using System.Linq; @@ -51,7 +52,7 @@ namespace OSCADSharp.Transforms public override Vector3 Position() { - throw new NotImplementedException(); + return Matrix.GetRotatedPoint(this.obj.Position(), this.Angle.X, this.Angle.Y, this.Angle.Z); } } } From 12eb89adbb07289f0182dcd3c1d3c8cb9788d94f Mon Sep 17 00:00:00 2001 From: Michael L Smith Date: Mon, 15 Feb 2016 20:30:46 -0800 Subject: [PATCH 06/13] Added some tests for known expected interpolation positions. --- OSCADSharp/OSCADSharp.ConsoleTests/Program.cs | 2 +- .../InterpolationTests.cs | 119 ++++++++++++++++++ .../OSCADSharp.UnitTests.csproj | 1 + 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 OSCADSharp/OSCADSharp.UnitTests/InterpolationTests.cs diff --git a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs index 535df3f..024607b 100644 --- a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs +++ b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs @@ -13,7 +13,7 @@ namespace OSCADSharp.ConsoleTests { static void Main(string[] args) { - var cube = new Cube(50, 50, 50, true).Translate(30, 30, 30).Rotate(25, 45, -90); + var cube = new Cube(13, 13, 13).Rotate(90, 37.5, -180); var pos = cube.Position(); var cyl1 = new Cylinder(1, 100, true).Translate(pos); diff --git a/OSCADSharp/OSCADSharp.UnitTests/InterpolationTests.cs b/OSCADSharp/OSCADSharp.UnitTests/InterpolationTests.cs new file mode 100644 index 0000000..396369a --- /dev/null +++ b/OSCADSharp/OSCADSharp.UnitTests/InterpolationTests.cs @@ -0,0 +1,119 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OSCADSharp.Solids; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OSCADSharp.UnitTests +{ + [TestClass] + public class InterpolationTests + { + //Positive X rotation + [TestMethod] + public void Interpolation_RotateOnXAxis() + { + var cube = new Cube(9, 9, 9).Rotate(90, 0, 0); + + //Rotating on X axis by 90 should shift the center of the cube on the negative Y quadrant + Assert.AreEqual(new Vector3(4.5, -4.5, 4.5), cube.Position()); + } + + //Negative X rotation + [TestMethod] + public void Interpolation_NegativeRotationOnXAxis() + { + var cube = new Cube(11, 11, 11).Rotate(-90, 0, 0); + + //Rotating on X axis by -90 should shift the center of the cube on the negative Z quadrant + Assert.AreEqual(new Vector3(5.5, 5.5, -5.5), cube.Position()); + } + + //Y Rotation + [TestMethod] + public void Interpolation_PositiveYRotationWithTallCube() + { + var cube = new Cube(10, 12, 23).Rotate(0, 90, 0); + + //Rotating on Y axis by 90 should shift the center of the cube on the negative Z quadrant + Assert.AreEqual(new Vector3(11.5, 6, -5), cube.Position()); + } + + //Negative Y rotation + [TestMethod] + public void Interpolation_NegativeYRotationWithWideCube() + { + var cube = new Cube(10, 30, 15).Rotate(0, -90, 0); + + //Rotating on Y axis by -90 should shift the center of the cube on the negative X quadrant + Assert.AreEqual(new Vector3(-7.5, 15, 5), cube.Position()); + } + + //Z Rotation + [TestMethod] + public void Interpolation_ZRotationWithLongCube() + { + var cube = new Cube(10, 5, 2).Rotate(0, 0, 115); + + //Rotating on Z axis by 90 should shift the center of the cube on the negative X quadrant + Assert.AreEqual(new Vector3(-4.37886077629512, 3.4749932808315, 1), cube.Position()); + } + + //Negative Z rotation + [TestMethod] + public void Interpolation_NegativeZRotation() + { + var cube = new Cube(10, 5, 2).Rotate(0, 0, -95); + + //Rotating on Z axis by 90 should shift the center of the cube on the negative Y quadrant + Assert.AreEqual(new Vector3(2.05470803149107, -5.19886284732787, 1), cube.Position()); + } + + //Centered rotation (no change) + [TestMethod] + public void Interpolation_CenteredCubePositionNotUpdatedWhenRotated() + { + var cube = new Cube(5, 20, 20, true).Rotate(15, -120, 270); + + Assert.AreEqual(new Vector3(), cube.Position()); + } + + //X and Y rotation + [TestMethod] + public void Interpolation_XAndYRotation() + { + var cube = new Cube(5, 5, 5).Rotate(120, 45, 0); + + Assert.AreEqual(new Vector3(2.41481456572267, -3.4150635094611, -1.12071934021007), cube.Position()); + } + + //Y and Z rotation + [TestMethod] + public void Interpolation_YandZRotation() + { + var cube = new Cube(13, 13, 13).Rotate(0, 270, -35); + + Assert.AreEqual(new Vector3(-1.59624145159665, 9.05273512416025, 6.5), cube.Position()); + } + + //X and Z rotation + [TestMethod] + public void Interpolation_XandZRotation() + { + var cube = new Cube(13, 13, 13).Rotate(-145, 0, 190); + + Assert.AreEqual(new Vector3(-6.67843481376553, 0.443277802376793, -9.05273512416025), cube.Position()); + } + + //X, Y and Z rotation + [TestMethod] + public void Interpolation_XYZRotation() + { + var cube = new Cube(13, 13, 13).Rotate(90, 37.5, -180); + + Assert.AreEqual(new Vector3(-9.11374600044971, 6.5, 1.19984742333634), cube.Position()); + } + } +} diff --git a/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj b/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj index 31cac6c..bdc0d30 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj +++ b/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj @@ -55,6 +55,7 @@ + From 8831610bdaf9b5878cc9a8dc7d737075290fd301 Mon Sep 17 00:00:00 2001 From: Michael L Smith Date: Mon, 15 Feb 2016 21:00:43 -0800 Subject: [PATCH 07/13] + Implemented Position on Cylinder, Sphere, Text3D + Made the executive decision that Text3D in OSCADSharp is always centered in script output, to facilitate correct position calculation. --- OSCADSharp/OSCADSharp.ConsoleTests/Program.cs | 6 ++--- .../OSCADSharp.UnitTests/CylinderTests.cs | 16 ++++++++++++++ .../OSCADSharp.UnitTests.csproj | 1 + .../OSCADSharp.UnitTests/SphereTests.cs | 8 +++++++ .../OSCADSharp.UnitTests/Text3DTests.cs | 22 +++++++++++++++++++ OSCADSharp/OSCADSharp/Solids/Cylinder.cs | 12 +++++++++- OSCADSharp/OSCADSharp/Solids/Sphere.cs | 2 +- OSCADSharp/OSCADSharp/Solids/Text3D.cs | 14 +++++++++++- 8 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 OSCADSharp/OSCADSharp.UnitTests/Text3DTests.cs diff --git a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs index 024607b..650ae6b 100644 --- a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs +++ b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs @@ -13,15 +13,15 @@ namespace OSCADSharp.ConsoleTests { static void Main(string[] args) { - var cube = new Cube(13, 13, 13).Rotate(90, 37.5, -180); + var obj = new Text3D("Hello, it's Meeeee."); - var pos = cube.Position(); + var pos = obj.Position(); var cyl1 = new Cylinder(1, 100, true).Translate(pos); var cyl2 = new Cylinder(1, 100, true).Rotate(0, 90, 0).Translate(pos); var cyl3 = new Cylinder(1, 100, true).Rotate(90, 0, 0).Translate(pos); var axisHelper = cyl1.Union(cyl2, cyl3).Color("Red"); - string script = cube.Union(axisHelper).ToString(); + string script = obj.Union(axisHelper).ToString(); File.WriteAllLines("test.scad", new string[] { script.ToString() }); //Console.ReadKey(); diff --git a/OSCADSharp/OSCADSharp.UnitTests/CylinderTests.cs b/OSCADSharp/OSCADSharp.UnitTests/CylinderTests.cs index ff3f83b..78396c5 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/CylinderTests.cs +++ b/OSCADSharp/OSCADSharp.UnitTests/CylinderTests.cs @@ -23,5 +23,21 @@ namespace OSCADSharp.UnitTests Assert.IsTrue(script.Contains("h = 12.1")); Assert.IsTrue(script.Contains("center = true")); } + + [TestMethod] + public void Cylinder_UncenteredPositionZValueIsHalfTheHeight() + { + var cylinder = new Cylinder(3, 40); + + Assert.AreEqual(new Vector3(0, 0, 20), cylinder.Position()); + } + + [TestMethod] + public void Cylinder_CenteredCylinderPositionIsZero() + { + var cylinder = new Cylinder(5, 20, true); + + Assert.AreEqual(new Vector3(), cylinder.Position()); + } } } diff --git a/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj b/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj index bdc0d30..6822582 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj +++ b/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj @@ -59,6 +59,7 @@ + diff --git a/OSCADSharp/OSCADSharp.UnitTests/SphereTests.cs b/OSCADSharp/OSCADSharp.UnitTests/SphereTests.cs index 292fe69..1e87047 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/SphereTests.cs +++ b/OSCADSharp/OSCADSharp.UnitTests/SphereTests.cs @@ -69,5 +69,13 @@ namespace OSCADSharp.UnitTests Assert.IsTrue(sphere.IsSameAs(clone)); } + + [TestMethod] + public void Sphere_PositionIsAtZero() + { + var sphere = new Sphere(); + + Assert.AreEqual(new Vector3(), sphere.Position()); + } } } diff --git a/OSCADSharp/OSCADSharp.UnitTests/Text3DTests.cs b/OSCADSharp/OSCADSharp.UnitTests/Text3DTests.cs new file mode 100644 index 0000000..e8ebcf3 --- /dev/null +++ b/OSCADSharp/OSCADSharp.UnitTests/Text3DTests.cs @@ -0,0 +1,22 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OSCADSharp.Solids; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OSCADSharp.UnitTests +{ + [TestClass] + public class Text3DTests + { + [TestMethod] + public void Text_PositionIsCentered() + { + var text = new Text3D("Bom chicka bow wow"); + + Assert.AreEqual(new Vector3(), text.Position()); + } + } +} diff --git a/OSCADSharp/OSCADSharp/Solids/Cylinder.cs b/OSCADSharp/OSCADSharp/Solids/Cylinder.cs index cd64f00..aaf6899 100644 --- a/OSCADSharp/OSCADSharp/Solids/Cylinder.cs +++ b/OSCADSharp/OSCADSharp/Solids/Cylinder.cs @@ -140,7 +140,17 @@ namespace OSCADSharp.Solids public override Vector3 Position() { - throw new NotImplementedException(); + Vector3 position; + if (this.Center == false) + { + position = new Vector3(0, 0, this.Height / 2); + } + else + { + position = new Vector3(); + } + + return position; } #endregion } diff --git a/OSCADSharp/OSCADSharp/Solids/Sphere.cs b/OSCADSharp/OSCADSharp/Solids/Sphere.cs index c397449..6316efc 100644 --- a/OSCADSharp/OSCADSharp/Solids/Sphere.cs +++ b/OSCADSharp/OSCADSharp/Solids/Sphere.cs @@ -83,7 +83,7 @@ namespace OSCADSharp.Solids public override Vector3 Position() { - throw new NotImplementedException(); + return new Vector3(); } #endregion } diff --git a/OSCADSharp/OSCADSharp/Solids/Text3D.cs b/OSCADSharp/OSCADSharp/Solids/Text3D.cs index 18fd767..1468921 100644 --- a/OSCADSharp/OSCADSharp/Solids/Text3D.cs +++ b/OSCADSharp/OSCADSharp/Solids/Text3D.cs @@ -116,6 +116,11 @@ namespace OSCADSharp.Solids sb.Append("\""); appendIfValueNotNullOrEmpty("size", this.Size?.ToString(), sb); + // Text is always centered in OSCADSharp to ensure correctness of + // position interpolation + appendIfValueNotNullOrEmpty("halign", "\"center\"", sb); + appendIfValueNotNullOrEmpty("valign", "\"center\"", sb); + appendIfValueNotNullOrEmpty("font", this.Font, sb); appendIfValueNotNullOrEmpty("spacing", this.Spacing?.ToString(), sb); appendIfValueNotNullOrEmpty("direction", this.TextDirection?.ToString(), sb); @@ -127,9 +132,16 @@ namespace OSCADSharp.Solids return formatter.ToString(); } + /// + /// In reaction to the need for this value to be correct, halign and valign will always + /// be "center" by default, since non-centered text would vary dramatically in position based upon + /// the font of the text + /// - MLS 2/15/2016 + /// + /// public override Vector3 Position() { - throw new NotImplementedException(); + return new Vector3(); } #endregion } From 294ae7e3577ff08ee7bb9242fc79614b6e8b141f Mon Sep 17 00:00:00 2001 From: Michael L Smith Date: Mon, 15 Feb 2016 21:18:13 -0800 Subject: [PATCH 08/13] Several more Position implementations --- .../Scripting/MultiBlockStatementObject.cs | 3 +- OSCADSharp/OSCADSharp/Spatial/Vector3.cs | 28 ++++++++++++++++++- .../Transforms/LinearExtrudedObject.cs | 2 +- .../OSCADSharp/Transforms/ResizedObject.cs | 2 +- .../OSCADSharp/Transforms/ScaledObject.cs | 2 +- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/OSCADSharp/OSCADSharp/Scripting/MultiBlockStatementObject.cs b/OSCADSharp/OSCADSharp/Scripting/MultiBlockStatementObject.cs index 4399fcc..c3a4cea 100644 --- a/OSCADSharp/OSCADSharp/Scripting/MultiBlockStatementObject.cs +++ b/OSCADSharp/OSCADSharp/Scripting/MultiBlockStatementObject.cs @@ -46,7 +46,8 @@ namespace OSCADSharp.Scripting public override Vector3 Position() { - throw new NotImplementedException(); + var positions = this.children.Select(child => child.Position()); + return Vector3.Average(positions.ToArray()); } } } diff --git a/OSCADSharp/OSCADSharp/Spatial/Vector3.cs b/OSCADSharp/OSCADSharp/Spatial/Vector3.cs index dbf858c..3f27e7b 100644 --- a/OSCADSharp/OSCADSharp/Spatial/Vector3.cs +++ b/OSCADSharp/OSCADSharp/Spatial/Vector3.cs @@ -46,6 +46,32 @@ namespace OSCADSharp return new Vector3(this.X, this.Y, this.Z); } + /// + /// Returns the average position of the provided positions + /// + /// + /// + public static Vector3 Average(params Vector3[] positions) + { + if(positions == null || positions.Length == 0) + { + return null; + } + else if (positions.Length == 1) + { + return positions[0]; + } + + var sum = new Vector3(); + + foreach (var pos in positions) + { + sum += pos; + } + + return new Vector3(sum.X / positions.Length, sum.Y / positions.Length, sum.Z / positions.Length); + } + #region Operators/Overrides public override bool Equals(object obj) { @@ -81,7 +107,7 @@ namespace OSCADSharp return new Vector3(left.X - right.X, left.Y - right.Y, left.Z - right.Z); } #endregion - + internal Matrix ToMatrix() { double[] coords = { this.X, this.Y, this.Z, 0 }; diff --git a/OSCADSharp/OSCADSharp/Transforms/LinearExtrudedObject.cs b/OSCADSharp/OSCADSharp/Transforms/LinearExtrudedObject.cs index 25a6a19..d1506b2 100644 --- a/OSCADSharp/OSCADSharp/Transforms/LinearExtrudedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/LinearExtrudedObject.cs @@ -50,7 +50,7 @@ namespace OSCADSharp.Transforms public override Vector3 Position() { - throw new NotImplementedException(); + throw new NotSupportedException(); } } } diff --git a/OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs b/OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs index a5bd317..506bdb3 100644 --- a/OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs @@ -51,7 +51,7 @@ namespace OSCADSharp.Transforms public override Vector3 Position() { - throw new NotImplementedException(); + return obj.Position(); } } } diff --git a/OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs b/OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs index 563d0a4..ed30e60 100644 --- a/OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs @@ -51,7 +51,7 @@ namespace OSCADSharp.Transforms public override Vector3 Position() { - throw new NotImplementedException(); + return obj.Position(); } } } From 07c845bcbdf3f284f11a2e0b9ea620299b37af90 Mon Sep 17 00:00:00 2001 From: Michael L Smith Date: Mon, 15 Feb 2016 21:45:38 -0800 Subject: [PATCH 09/13] + Position interpolation for single-axis mirroring. --- OSCADSharp/OSCADSharp.ConsoleTests/Program.cs | 2 +- .../OSCADSharp.UnitTests/MirrorTests.cs | 35 +++++++++++++++++++ .../OSCADSharp.UnitTests.csproj | 1 + .../OSCADSharp/Transforms/MirroredObject.cs | 11 +++++- 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 OSCADSharp/OSCADSharp.UnitTests/MirrorTests.cs diff --git a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs index 650ae6b..a0748ee 100644 --- a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs +++ b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs @@ -13,7 +13,7 @@ namespace OSCADSharp.ConsoleTests { static void Main(string[] args) { - var obj = new Text3D("Hello, it's Meeeee."); + var obj = new Cube(5, 10, 20).Mirror(0, 0, 1); var pos = obj.Position(); var cyl1 = new Cylinder(1, 100, true).Translate(pos); diff --git a/OSCADSharp/OSCADSharp.UnitTests/MirrorTests.cs b/OSCADSharp/OSCADSharp.UnitTests/MirrorTests.cs new file mode 100644 index 0000000..1f972cb --- /dev/null +++ b/OSCADSharp/OSCADSharp.UnitTests/MirrorTests.cs @@ -0,0 +1,35 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OSCADSharp.Solids; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OSCADSharp.UnitTests +{ + [TestClass] + public class MirrorTests + { + [TestMethod] + public void Mirror_SingleAxisMirrorInvertsPosition() + { + var cube = new Cube(5, 10, 20); + var xMirror = cube.Clone().Mirror(1, 0, 0); + var yMirror = cube.Clone().Mirror(0, 1, 0); + var zMirror = cube.Clone().Mirror(0, 0, 1); + + var pos = cube.Position().Clone(); + pos.X = -pos.X; + Assert.AreEqual(pos, xMirror.Position()); + + pos = cube.Position().Clone(); + pos.Y = -pos.Y; + Assert.AreEqual(pos, yMirror.Position()); + + pos = cube.Position().Clone(); + pos.Z = -pos.Z; + Assert.AreEqual(pos, zMirror.Position()); + } + } +} diff --git a/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj b/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj index 6822582..b2e1d2e 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj +++ b/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj @@ -56,6 +56,7 @@ + diff --git a/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs b/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs index 7eb1793..2412980 100644 --- a/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs @@ -1,4 +1,5 @@ using OSCADSharp.Scripting; +using OSCADSharp.Spatial; using System; using System.Collections.Generic; using System.Linq; @@ -50,9 +51,17 @@ namespace OSCADSharp.Transforms return new MirroredObject(obj, this.Normal); } + // TODO: This will yield incorrect positions if mirroring on multiple axes + // fix mirrored positions for multiple-axis mirroring public override Vector3 Position() { - throw new NotImplementedException(); + var pos = obj.Position(); + + double x = this.Normal.X != 0 ? pos.X * -1 : pos.X; + double y = this.Normal.Y != 0 ? pos.Y * -1 : pos.Y; + double z = this.Normal.Z != 0 ? pos.Z * -1 : pos.Z; + + return new Vector3(x, y, z); } } } From 8e5aa0a2f37fdcd913e8f8ccab1dd26f8c3843c0 Mon Sep 17 00:00:00 2001 From: Mike Smith Date: Tue, 16 Feb 2016 17:37:21 -0800 Subject: [PATCH 10/13] + Added some additional Vector operations --- OSCADSharp/OSCADSharp/Spatial/Vector3.cs | 39 ++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/OSCADSharp/OSCADSharp/Spatial/Vector3.cs b/OSCADSharp/OSCADSharp/Spatial/Vector3.cs index 3f27e7b..82f4e65 100644 --- a/OSCADSharp/OSCADSharp/Spatial/Vector3.cs +++ b/OSCADSharp/OSCADSharp/Spatial/Vector3.cs @@ -72,6 +72,26 @@ namespace OSCADSharp return new Vector3(sum.X / positions.Length, sum.Y / positions.Length, sum.Z / positions.Length); } + /// + /// Returns the unit vector for this vector + /// + /// + public Vector3 Normalize() + { + if(this.X == 0 && this.Y == 0 && this.Z == 0) + { + return this; + } + + double sum = Math.Abs(this.X) + Math.Abs(this.Y) + Math.Abs(this.Z); + return new Vector3(this.X / sum, this.Y / sum, this.Z / sum); + } + + public double Dot(Vector3 other) + { + return this.X * other.X + this.Y * other.Y + this.Z * other.Z; + } + #region Operators/Overrides public override bool Equals(object obj) { @@ -96,7 +116,7 @@ namespace OSCADSharp left.Y == right.Y && left.Z == right.Z); } - + public static Vector3 operator +(Vector3 left, Vector3 right) { return new Vector3(left.X + right.X, left.Y + right.Y, left.Z + right.Z); @@ -106,8 +126,23 @@ namespace OSCADSharp { return new Vector3(left.X - right.X, left.Y - right.Y, left.Z - right.Z); } + + public static Vector3 operator *(Vector3 left, Vector3 right) + { + return new Vector3(left.X * right.X, left.Y * right.Y, left.Z * right.Z); + } + + public static Vector3 operator *(Vector3 left, double right) + { + return new Vector3(left.X * right, left.Y * right, left.Z * right); + } + + public static Vector3 operator *(double left, Vector3 right) + { + return new Vector3(left * right.X, left * right.Y, left * right.Z); + } #endregion - + internal Matrix ToMatrix() { double[] coords = { this.X, this.Y, this.Z, 0 }; From 2bbe452da6d3cf3d49fbe041d81f3dbdc89cc4ff Mon Sep 17 00:00:00 2001 From: Michael L Smith Date: Tue, 16 Feb 2016 19:34:33 -0800 Subject: [PATCH 11/13] + Added a NotSupportedException when Position is called on a mirrored object that's been mirrored on multiple axes + test --- OSCADSharp/OSCADSharp.UnitTests/MirrorTests.cs | 9 +++++++++ OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/OSCADSharp/OSCADSharp.UnitTests/MirrorTests.cs b/OSCADSharp/OSCADSharp.UnitTests/MirrorTests.cs index 1f972cb..dc2747b 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/MirrorTests.cs +++ b/OSCADSharp/OSCADSharp.UnitTests/MirrorTests.cs @@ -31,5 +31,14 @@ namespace OSCADSharp.UnitTests pos.Z = -pos.Z; Assert.AreEqual(pos, zMirror.Position()); } + + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void Mirror_MultiAxisPositionThrowsNotSupportedException() + { + var cube = new Cube(5, 10, 20); + + var pos = cube.Mirror(1, 1, 0).Position(); + } } } diff --git a/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs b/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs index 2412980..05f4dc7 100644 --- a/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs @@ -55,6 +55,11 @@ namespace OSCADSharp.Transforms // fix mirrored positions for multiple-axis mirroring public override Vector3 Position() { + if (this.isMoreThanOneAxis()) + { + throw new NotSupportedException("Getting the position of an object that's been mirrored on more than one axis is not currently supported."); + } + var pos = obj.Position(); double x = this.Normal.X != 0 ? pos.X * -1 : pos.X; @@ -63,5 +68,11 @@ namespace OSCADSharp.Transforms return new Vector3(x, y, z); } + + private bool isMoreThanOneAxis() + { + return (this.Normal.X != 0 && (this.Normal.Y != 0 || this.Normal.Z != 0)) || + (this.Normal.Y != 0 && (this.Normal.X != 0 || this.Normal.Z != 0)); + } } } From b6a454e8b973c12d1508d938502cfc9a4ced3850 Mon Sep 17 00:00:00 2001 From: Michael L Smith Date: Tue, 16 Feb 2016 19:54:34 -0800 Subject: [PATCH 12/13] + Added NotSupportedExceptions on all block statements except Hull and Union when Position() is called on them --- OSCADSharp/OSCADSharp.ConsoleTests/Program.cs | 5 ++++- .../OSCADSharp.UnitTests/DifferenceTests.cs | 19 +++++++++++++++++++ .../OSCADSharp.UnitTests/IntersectionTests.cs | 19 +++++++++++++++++++ .../OSCADSharp.UnitTests/MinkowskiTests.cs | 19 +++++++++++++++++++ .../OSCADSharp.UnitTests.csproj | 3 +++ OSCADSharp/OSCADSharp/Booleans/Difference.cs | 7 ++++++- .../OSCADSharp/Booleans/Intersection.cs | 5 +++++ .../Transforms/MinkowskiedObject.cs | 7 ++++++- 8 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 OSCADSharp/OSCADSharp.UnitTests/DifferenceTests.cs create mode 100644 OSCADSharp/OSCADSharp.UnitTests/IntersectionTests.cs create mode 100644 OSCADSharp/OSCADSharp.UnitTests/MinkowskiTests.cs diff --git a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs index a0748ee..7d1ff28 100644 --- a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs +++ b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs @@ -13,7 +13,10 @@ namespace OSCADSharp.ConsoleTests { static void Main(string[] args) { - var obj = new Cube(5, 10, 20).Mirror(0, 0, 1); + var obj = new Cube(5, 10, 20).Mirror(0, 0, 1).Mirror(0, 1, 0) + .Rotate(15, -45, 120).Translate(-20, 10, 15).Rotate(90, 15, 25) + .Translate(-10, -20, -20).Rotate(-90, -90, -45); + obj = obj.Minkowski(new Cube(1, 1, 5)); var pos = obj.Position(); var cyl1 = new Cylinder(1, 100, true).Translate(pos); diff --git a/OSCADSharp/OSCADSharp.UnitTests/DifferenceTests.cs b/OSCADSharp/OSCADSharp.UnitTests/DifferenceTests.cs new file mode 100644 index 0000000..16b5c31 --- /dev/null +++ b/OSCADSharp/OSCADSharp.UnitTests/DifferenceTests.cs @@ -0,0 +1,19 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OSCADSharp.Solids; + +namespace OSCADSharp.UnitTests +{ + [TestClass] + public class DifferenceTests + { + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void Difference_PositionThrowsNotSupportedException() + { + var diff = new Sphere().Difference(new Cube()); + + var pos = diff.Position(); + } + } +} diff --git a/OSCADSharp/OSCADSharp.UnitTests/IntersectionTests.cs b/OSCADSharp/OSCADSharp.UnitTests/IntersectionTests.cs new file mode 100644 index 0000000..fadd682 --- /dev/null +++ b/OSCADSharp/OSCADSharp.UnitTests/IntersectionTests.cs @@ -0,0 +1,19 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OSCADSharp.Solids; + +namespace OSCADSharp.UnitTests +{ + [TestClass] + public class IntersectionTests + { + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void Intersection_PositionThrowsNotSupportedException() + { + var obj = new Sphere().Intersection(new Text3D("Sup")); + + var pos = obj.Position(); + } + } +} diff --git a/OSCADSharp/OSCADSharp.UnitTests/MinkowskiTests.cs b/OSCADSharp/OSCADSharp.UnitTests/MinkowskiTests.cs new file mode 100644 index 0000000..abbc9c7 --- /dev/null +++ b/OSCADSharp/OSCADSharp.UnitTests/MinkowskiTests.cs @@ -0,0 +1,19 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OSCADSharp.Solids; + +namespace OSCADSharp.UnitTests +{ + [TestClass] + public class MinkowskiTests + { + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void Minkowski_PositionThrowsNotSupportedException() + { + var obj = new Cylinder().Intersection(new Sphere()).Translate(0, 5, 5); + + var pos = obj.Position(); + } + } +} diff --git a/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj b/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj index b2e1d2e..f66616f 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj +++ b/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj @@ -62,6 +62,9 @@ + + + diff --git a/OSCADSharp/OSCADSharp/Booleans/Difference.cs b/OSCADSharp/OSCADSharp/Booleans/Difference.cs index 3877265..bd66924 100644 --- a/OSCADSharp/OSCADSharp/Booleans/Difference.cs +++ b/OSCADSharp/OSCADSharp/Booleans/Difference.cs @@ -18,6 +18,11 @@ namespace OSCADSharp.Booleans /// public Difference(IEnumerable children) : base("difference()", children) { - } + } + + public override Vector3 Position() + { + throw new NotSupportedException("Position is not supported on Differenced objects."); + } } } diff --git a/OSCADSharp/OSCADSharp/Booleans/Intersection.cs b/OSCADSharp/OSCADSharp/Booleans/Intersection.cs index a67f010..f5c0f72 100644 --- a/OSCADSharp/OSCADSharp/Booleans/Intersection.cs +++ b/OSCADSharp/OSCADSharp/Booleans/Intersection.cs @@ -19,5 +19,10 @@ namespace OSCADSharp.Booleans public Intersection(IEnumerable children) : base("intersection()", children) { } + + public override Vector3 Position() + { + throw new NotSupportedException("Position is not supported on Intersected objects."); + } } } diff --git a/OSCADSharp/OSCADSharp/Transforms/MinkowskiedObject.cs b/OSCADSharp/OSCADSharp/Transforms/MinkowskiedObject.cs index 1af5640..3b4693c 100644 --- a/OSCADSharp/OSCADSharp/Transforms/MinkowskiedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/MinkowskiedObject.cs @@ -15,6 +15,11 @@ namespace OSCADSharp.Transforms public MinkowskiedObject(IEnumerable children) : base("minkowski()", children) { - } + } + + public override Vector3 Position() + { + throw new NotSupportedException("Position is not supported on Minkowskied objects."); + } } } From 3024b7a5feb0a2b5e1586915644e7e73a9918f1d Mon Sep 17 00:00:00 2001 From: Michael L Smith Date: Tue, 16 Feb 2016 20:00:55 -0800 Subject: [PATCH 13/13] + Added one more test for position after lots of operations. --- OSCADSharp/OSCADSharp.ConsoleTests/Program.cs | 1 - OSCADSharp/OSCADSharp.UnitTests/InterpolationTests.cs | 11 +++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs index 7d1ff28..1516b69 100644 --- a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs +++ b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs @@ -16,7 +16,6 @@ namespace OSCADSharp.ConsoleTests var obj = new Cube(5, 10, 20).Mirror(0, 0, 1).Mirror(0, 1, 0) .Rotate(15, -45, 120).Translate(-20, 10, 15).Rotate(90, 15, 25) .Translate(-10, -20, -20).Rotate(-90, -90, -45); - obj = obj.Minkowski(new Cube(1, 1, 5)); var pos = obj.Position(); var cyl1 = new Cylinder(1, 100, true).Translate(pos); diff --git a/OSCADSharp/OSCADSharp.UnitTests/InterpolationTests.cs b/OSCADSharp/OSCADSharp.UnitTests/InterpolationTests.cs index 396369a..f64e3d8 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/InterpolationTests.cs +++ b/OSCADSharp/OSCADSharp.UnitTests/InterpolationTests.cs @@ -115,5 +115,16 @@ namespace OSCADSharp.UnitTests Assert.AreEqual(new Vector3(-9.11374600044971, 6.5, 1.19984742333634), cube.Position()); } + + [TestMethod] + public void Interpolation_PositionAfterLotsOfOperations() + { + var obj = new Cube(5, 10, 20).Mirror(0, 0, 1).Mirror(0, 1, 0) + .Rotate(15, -45, 120).Translate(-20, 10, 15).Rotate(90, 15, 25) + .Translate(-10, -20, -20).Rotate(-90, -90, -45); + + var position = obj.Position(); + Assert.AreEqual(new Vector3(-21.7567866493247, 28.2686425980997, -21.6189570529939), position); + } } }