Merge pull request #1 from Exolun/PositionInterpolation

Position interpolation
This commit is contained in:
Michael Smith 2016-02-16 20:08:20 -08:00
commit 1440def15d
31 changed files with 798 additions and 73 deletions

View File

@ -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();

View File

@ -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());
}
}
}

View File

@ -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());
}
}
}

View 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();
}
}
}

View 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);
}
}
}

View 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();
}
}
}

View 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();
}
}
}

View 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();
}
}
}

View File

@ -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">

View File

@ -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());
}
}
}

View 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());
}
}
}

View File

@ -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.");
}
}
}

View File

@ -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.");
}
}
}

View File

@ -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
///

View File

@ -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" />

View File

@ -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());
}
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -80,6 +80,11 @@ namespace OSCADSharp.Solids
Radius = this.Radius
};
}
public override Vector3 Position()
{
return new Vector3();
}
#endregion
}
}

View File

@ -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
}
}

View 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
}
}

View 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());
}
}
}

View File

@ -50,5 +50,10 @@ namespace OSCADSharp.Transforms
{
return new ColoredObject(obj, this.ColorName, this.Opacity);
}
public override Vector3 Position()
{
return this.obj.Position();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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.");
}
}
}

View File

@ -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));
}
}
}

View File

@ -48,5 +48,10 @@ namespace OSCADSharp.Transforms
{
return new ResizedObject(obj, this.Size);
}
public override Vector3 Position()
{
return obj.Position();
}
}
}

View File

@ -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);
}
}
}

View File

@ -48,5 +48,10 @@ namespace OSCADSharp.Transforms
{
return new ScaledObject(obj, this.ScaleFactor);
}
public override Vector3 Position()
{
return obj.Position();
}
}
}

View File

@ -45,5 +45,10 @@ namespace OSCADSharp.Transforms
{
return new TranslatedObject(obj, this.Vector);
}
public override Vector3 Position()
{
return this.obj.Position() + this.Vector;
}
}
}

View File

@ -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());
}
}
}