public static PrimitiveEllipse Project(PrimitiveEllipse ellipse, Matrix4 transform) { // brute-force the endpoints var fromUnit = Matrix4.CreateScale(1.0, 1.0, 0.0) * transform * ellipse.FromUnitCircle; var center = transform.Transform(ellipse.Center); var minPoint = fromUnit.Transform(new Point(MathHelper.COS[0], MathHelper.SIN[0], 0)); var maxPoint = minPoint; var minDistance = (minPoint - center).LengthSquared; var maxDistance = minDistance; for (int i = 1; i < 360; i++) { var next = fromUnit.Transform(new Point(MathHelper.COS[i], MathHelper.SIN[i], 0)); var dist = (next - center).LengthSquared; if (dist < minDistance) { minPoint = next; minDistance = dist; } if (dist > maxDistance) { maxPoint = next; maxDistance = dist; } } var majorAxis = maxPoint - center; var minorAxisRatio = Math.Sqrt(minDistance) / Math.Sqrt(maxDistance); var startAngle = ellipse.StartAngle; var endAngle = ellipse.EndAngle; // projection looks like a circle if (Math.Abs(maxDistance - minDistance) < MathHelper.Epsilon * 1000) // TODO: need a better way to do this { majorAxis = new Vector(majorAxis.Length, 0.0, 0.0); // right vector minorAxisRatio = 1.0; } // correct start/end angles if (!ellipse.IsClosed) { var tempEllipse = new PrimitiveEllipse(center, majorAxis, Vector.ZAxis, minorAxisRatio, 0.0, MathHelper.ThreeSixty, ellipse.Color); var majorAngle = majorAxis.ToAngle(); var startPoint = transform.Transform(ellipse.StartPoint()); var endPoint = transform.Transform(ellipse.EndPoint()); var toUnit = tempEllipse.FromUnitCircle.Inverse(); var startUnit = (Vector)toUnit.Transform(startPoint); var endUnit = (Vector)toUnit.Transform(endPoint); startAngle = (startUnit.ToAngle() - majorAngle).CorrectAngleDegrees(); endAngle = (endUnit.ToAngle() - majorAngle).CorrectAngleDegrees(); } return(new PrimitiveEllipse(center, majorAxis, Vector.ZAxis, minorAxisRatio, startAngle, endAngle, ellipse.Color)); }
public void EllipseGetPointTest() { var el = new PrimitiveEllipse(Point.Origin, 1.0, 0.0, 180.0, Vector.ZAxis); Assert.True(el.StartPoint().CloseTo(new Point(1.0, 0.0, 0.0))); Assert.True(el.EndPoint().CloseTo(new Point(-1.0, 0.0, 0.0))); Assert.True(el.GetPoint(90.0).CloseTo(new Point(0.0, 1.0, 0.0))); el = new PrimitiveEllipse(new Point(1.0, 1.0, 0.0), 1.0, 0.0, 180.0, Vector.ZAxis); Assert.True(el.StartPoint().CloseTo(new Point(2.0, 1.0, 0.0))); Assert.True(el.EndPoint().CloseTo(new Point(0.0, 1.0, 0.0))); Assert.True(el.GetPoint(90.0).CloseTo(new Point(1.0, 2.0, 0.0))); }