mirror of
https://github.com/eliasstepanik/OSCADSharpDotnet7.git
synced 2026-01-14 06:58:34 +00:00
Merge pull request #1 from Exolun/PositionInterpolation
Position interpolation
This commit is contained in:
commit
1440def15d
@ -13,11 +13,17 @@ 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 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);
|
||||
|
||||
string script = hull.ToString();
|
||||
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 = obj.Union(axisHelper).ToString();
|
||||
|
||||
File.WriteAllLines("test.scad", new string[] { script.ToString() });
|
||||
//Console.ReadKey();
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
OSCADSharp/OSCADSharp.UnitTests/DifferenceTests.cs
Normal file
19
OSCADSharp/OSCADSharp.UnitTests/DifferenceTests.cs
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
130
OSCADSharp/OSCADSharp.UnitTests/InterpolationTests.cs
Normal file
130
OSCADSharp/OSCADSharp.UnitTests/InterpolationTests.cs
Normal file
@ -0,0 +1,130 @@
|
||||
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());
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
OSCADSharp/OSCADSharp.UnitTests/IntersectionTests.cs
Normal file
19
OSCADSharp/OSCADSharp.UnitTests/IntersectionTests.cs
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
19
OSCADSharp/OSCADSharp.UnitTests/MinkowskiTests.cs
Normal file
19
OSCADSharp/OSCADSharp.UnitTests/MinkowskiTests.cs
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
44
OSCADSharp/OSCADSharp.UnitTests/MirrorTests.cs
Normal file
44
OSCADSharp/OSCADSharp.UnitTests/MirrorTests.cs
Normal file
@ -0,0 +1,44 @@
|
||||
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());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(NotSupportedException))]
|
||||
public void Mirror_MultiAxisPositionThrowsNotSupportedException()
|
||||
{
|
||||
var cube = new Cube(5, 10, 20);
|
||||
|
||||
var pos = cube.Mirror(1, 1, 0).Position();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,10 +55,16 @@
|
||||
<Compile Include="CubeTests.cs" />
|
||||
<Compile Include="CylinderTests.cs" />
|
||||
<Compile Include="HullTests.cs" />
|
||||
<Compile Include="InterpolationTests.cs" />
|
||||
<Compile Include="MirrorTests.cs" />
|
||||
<Compile Include="OSCADObjectTests.cs" />
|
||||
<Compile Include="SphereTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Text3DTests.cs" />
|
||||
<Compile Include="UnionTests.cs" />
|
||||
<Compile Include="DifferenceTests.cs" />
|
||||
<Compile Include="IntersectionTests.cs" />
|
||||
<Compile Include="MinkowskiTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OSCADSharp\OSCADSharp.csproj">
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
22
OSCADSharp/OSCADSharp.UnitTests/Text3DTests.cs
Normal file
22
OSCADSharp/OSCADSharp.UnitTests/Text3DTests.cs
Normal file
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -18,6 +18,11 @@ namespace OSCADSharp.Booleans
|
||||
/// <param name="children"></param>
|
||||
public Difference(IEnumerable<OSCADObject> children) : base("difference()", children)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public override Vector3 Position()
|
||||
{
|
||||
throw new NotSupportedException("Position is not supported on Differenced objects.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,5 +19,10 @@ namespace OSCADSharp.Booleans
|
||||
public Intersection(IEnumerable<OSCADObject> children) : base("intersection()", children)
|
||||
{
|
||||
}
|
||||
|
||||
public override Vector3 Position()
|
||||
{
|
||||
throw new NotSupportedException("Position is not supported on Intersected objects.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,6 +204,16 @@ namespace OSCADSharp
|
||||
#endregion
|
||||
|
||||
#region Utility Methods
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract Vector3 Position();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of this object and all of its children
|
||||
///
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Sizes.cs" />
|
||||
<Compile Include="Spatial\Matrix.cs" />
|
||||
<Compile Include="Transforms\HulledObject.cs" />
|
||||
<Compile Include="Transforms\IMimicer.cs" />
|
||||
<Compile Include="Transforms\LinearExtrudedObject.cs" />
|
||||
@ -62,7 +63,7 @@
|
||||
<Compile Include="Transforms\RotatedObject.cs" />
|
||||
<Compile Include="Transforms\ScaledObject.cs" />
|
||||
<Compile Include="Transforms\TranslatedObject.cs" />
|
||||
<Compile Include="Vector3.cs" />
|
||||
<Compile Include="Spatial\Vector3.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
|
||||
@ -43,5 +43,11 @@ namespace OSCADSharp.Scripting
|
||||
|
||||
return new MultiBlockStatementObject(this.outerStatement, childClones);
|
||||
}
|
||||
|
||||
public override Vector3 Position()
|
||||
{
|
||||
var positions = this.children.Select(child => child.Position());
|
||||
return Vector3.Average(positions.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,6 +76,21 @@ namespace OSCADSharp.Solids
|
||||
Center = this.Center
|
||||
};
|
||||
}
|
||||
|
||||
public override Vector3 Position()
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,6 +137,21 @@ namespace OSCADSharp.Solids
|
||||
Center = this.Center
|
||||
};
|
||||
}
|
||||
|
||||
public override Vector3 Position()
|
||||
{
|
||||
Vector3 position;
|
||||
if (this.Center == false)
|
||||
{
|
||||
position = new Vector3(0, 0, this.Height / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
position = new Vector3();
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,6 +80,11 @@ namespace OSCADSharp.Solids
|
||||
Radius = this.Radius
|
||||
};
|
||||
}
|
||||
|
||||
public override Vector3 Position()
|
||||
{
|
||||
return new Vector3();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,6 +59,7 @@ namespace OSCADSharp.Solids
|
||||
public string Language { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates 3d text with the default parameters
|
||||
@ -115,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);
|
||||
@ -125,6 +131,18 @@ namespace OSCADSharp.Solids
|
||||
var formatter = new SingleBlockFormatter(String.Format("linear_extrude(height = {0})", 1), sb.ToString());
|
||||
return formatter.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override Vector3 Position()
|
||||
{
|
||||
return new Vector3();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
172
OSCADSharp/OSCADSharp/Spatial/Matrix.cs
Normal file
172
OSCADSharp/OSCADSharp/Spatial/Matrix.cs
Normal file
@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OSCADSharp.Spatial
|
||||
{
|
||||
/// <summary>
|
||||
/// An n-dimensional Matrix for performing operations on doubles that
|
||||
/// represent spatial positions
|
||||
/// </summary>
|
||||
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<double> 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<double> result = new List<double>();
|
||||
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.Add(0);
|
||||
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; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a transformation matrix for performing rotations on the X-Axis
|
||||
/// (Assuming you are in a right-handed 3D world)
|
||||
/// </summary>
|
||||
/// <param name="angle">Degrees of rotation</param>
|
||||
/// <returns>Transformation matrix to perform the rotation</returns>
|
||||
internal static Matrix XRotation(double angle)
|
||||
{
|
||||
if (angle == 0)
|
||||
return Identity;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a transformation matrix for performing rotations on the Y-Axis
|
||||
/// (Assuming you are in a right-handed 3D world)
|
||||
/// </summary>
|
||||
/// <param name="angle">Degrees of rotation</param>
|
||||
/// <returns>Transformation matrix to perform the rotation</returns>
|
||||
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,
|
||||
0, 1, 0, 0,
|
||||
Math.Sin(radAngle), 0, Math.Cos(radAngle), 0,
|
||||
0, 0, 0, 1
|
||||
};
|
||||
|
||||
return new Matrix(rotationArr, 4, 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a transformation matrix for performing rotations on the Z-Axis
|
||||
/// (Assuming you are in a right-handed 3D world)
|
||||
/// </summary>
|
||||
/// <param name="angle">Degrees of rotation</param>
|
||||
/// <returns>Transformation matrix to perform the rotation</returns>
|
||||
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,
|
||||
-Math.Sin(radAngle), Math.Cos(radAngle), 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
};
|
||||
|
||||
return new Matrix(rotationArr, 4, 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a point's position after rotations have been applied
|
||||
/// </summary>
|
||||
/// <param name="point">Point to rotate</param>
|
||||
/// <param name="xAngle"></param>
|
||||
/// <param name="yAngle"></param>
|
||||
/// <param name="zAngle"></param>
|
||||
/// <returns>Point after rotation</returns>
|
||||
internal static Vector3 GetRotatedPoint(Vector3 point, double xAngle, double yAngle, double zAngle)
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
157
OSCADSharp/OSCADSharp/Spatial/Vector3.cs
Normal file
157
OSCADSharp/OSCADSharp/Spatial/Vector3.cs
Normal file
@ -0,0 +1,157 @@
|
||||
using OSCADSharp.Spatial;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OSCADSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A Three-Dimensional vector
|
||||
///
|
||||
/// Can be used to represent a direction, or a point in space
|
||||
/// </summary>
|
||||
public class Vector3
|
||||
{
|
||||
#region Attributes
|
||||
public double X { get; set; }
|
||||
public double Y { get; set; }
|
||||
public double Z { get; set; }
|
||||
#endregion
|
||||
|
||||
public Vector3(double x = 0, double y = 0, double z = 0)
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
this.Z = z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Negates the values of this vector, returning an inverse of it
|
||||
/// </summary>
|
||||
/// <returns>A negated vector</returns>
|
||||
public Vector3 Negate()
|
||||
{
|
||||
return new Vector3(-this.X, -this.Y, -this.Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of this vector that's a new instance
|
||||
/// with the same values
|
||||
/// </summary>
|
||||
/// <returns>A clone of this vector</returns>
|
||||
public Vector3 Clone()
|
||||
{
|
||||
return new Vector3(this.X, this.Y, this.Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the average position of the provided positions
|
||||
/// </summary>
|
||||
/// <param name="positions"></param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the unit vector for this vector
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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, 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 };
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -50,5 +50,10 @@ namespace OSCADSharp.Transforms
|
||||
{
|
||||
return new ColoredObject(obj, this.ColorName, this.Opacity);
|
||||
}
|
||||
|
||||
public override Vector3 Position()
|
||||
{
|
||||
return this.obj.Position();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,11 @@ namespace OSCADSharp.Transforms
|
||||
|
||||
public MinkowskiedObject(IEnumerable<OSCADObject> children) : base("minkowski()", children)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public override Vector3 Position()
|
||||
{
|
||||
throw new NotSupportedException("Position is not supported on Minkowskied objects.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using OSCADSharp.Scripting;
|
||||
using OSCADSharp.Spatial;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -49,5 +50,29 @@ 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()
|
||||
{
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,5 +48,10 @@ namespace OSCADSharp.Transforms
|
||||
{
|
||||
return new ResizedObject(obj, this.Size);
|
||||
}
|
||||
|
||||
public override Vector3 Position()
|
||||
{
|
||||
return obj.Position();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using OSCADSharp.Scripting;
|
||||
using OSCADSharp.Spatial;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -48,5 +49,10 @@ namespace OSCADSharp.Transforms
|
||||
{
|
||||
return new RotatedObject(obj, this.Angle);
|
||||
}
|
||||
|
||||
public override Vector3 Position()
|
||||
{
|
||||
return Matrix.GetRotatedPoint(this.obj.Position(), this.Angle.X, this.Angle.Y, this.Angle.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,5 +48,10 @@ namespace OSCADSharp.Transforms
|
||||
{
|
||||
return new ScaledObject(obj, this.ScaleFactor);
|
||||
}
|
||||
|
||||
public override Vector3 Position()
|
||||
{
|
||||
return obj.Position();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,5 +45,10 @@ namespace OSCADSharp.Transforms
|
||||
{
|
||||
return new TranslatedObject(obj, this.Vector);
|
||||
}
|
||||
|
||||
public override Vector3 Position()
|
||||
{
|
||||
return this.obj.Position() + this.Vector;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OSCADSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A Three-Dimensional vector
|
||||
///
|
||||
/// Can be used to represent a direction, or a point in space
|
||||
/// </summary>
|
||||
public class Vector3
|
||||
{
|
||||
#region Attributes
|
||||
public double X { get; set; }
|
||||
public double Y { get; set; }
|
||||
public double Z { get; set; }
|
||||
#endregion
|
||||
|
||||
public Vector3(double x = 0, double y = 0, double z = 0)
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
this.Z = z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Negates the values of this vector, returning an inverse of it
|
||||
/// </summary>
|
||||
/// <returns>A negated vector</returns>
|
||||
public Vector3 Negate()
|
||||
{
|
||||
return new Vector3(-this.X, -this.Y, -this.Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of this vector that's a new instance
|
||||
/// with the same values
|
||||
/// </summary>
|
||||
/// <returns>A clone of this vector</returns>
|
||||
public Vector3 Clone()
|
||||
{
|
||||
return new Vector3(this.X, this.Y, this.Z);
|
||||
}
|
||||
|
||||
#region Operators
|
||||
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, Vector3 right)
|
||||
{
|
||||
return new Vector3(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("[X: {0}, Y: {1}, Z: {2}]", this.X.ToString(), this.Y.ToString(), this.Z.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user