Exemplo n.º 1
0
        /// <summary>
        /// Moves, scales, and/or rotates the current entity given a 3x3 transformation matrix and a translation vector.
        /// </summary>
        /// <param name="transformation">Transformation matrix.</param>
        /// <param name="translation">Translation vector.</param>
        /// <remarks>Matrix3 adopts the convention of using column vectors to represent a transformation matrix.</remarks>
        public override void TransformBy(Matrix3 transformation, Vector3 translation)
        {
            // NOTE: this is a generic implementation of the ellipse transformation,
            // for non rotated ellipses and/or uniform scaling the code can be simplified

            // rectangle that circumscribe the ellipse
            double semiMajorAxis = this.MajorAxis * 0.5;
            double semiMinorAxis = this.MinorAxis * 0.5;

            Vector2        p1        = new Vector2(-semiMajorAxis, semiMinorAxis);
            Vector2        p2        = new Vector2(semiMajorAxis, semiMinorAxis);
            Vector2        p3        = new Vector2(-semiMajorAxis, -semiMinorAxis);
            Vector2        p4        = new Vector2(semiMajorAxis, -semiMinorAxis);
            List <Vector2> ocsPoints = MathHelper.Transform(new[] { p1, p2, p3, p4 }, this.Rotation * MathHelper.DegToRad, CoordinateSystem.Object, CoordinateSystem.World);

            Vector3        p1Prime   = new Vector3(ocsPoints[0].X, ocsPoints[0].Y, 0.0);
            Vector3        p2Prime   = new Vector3(ocsPoints[1].X, ocsPoints[1].Y, 0.0);
            Vector3        p3Prime   = new Vector3(ocsPoints[2].X, ocsPoints[2].Y, 0.0);
            Vector3        p4Prime   = new Vector3(ocsPoints[3].X, ocsPoints[3].Y, 0.0);
            List <Vector3> wcsPoints = MathHelper.Transform(new[] { p1Prime, p2Prime, p3Prime, p4Prime }, this.Normal, CoordinateSystem.Object, CoordinateSystem.World);

            for (int i = 0; i < wcsPoints.Count; i++)
            {
                wcsPoints[i] += this.Center;

                wcsPoints[i]  = transformation * wcsPoints[i];
                wcsPoints[i] += translation;
            }

            Vector3 newNormal = transformation * this.Normal;

            if (Vector3.Equals(Vector3.Zero, newNormal))
            {
                newNormal = this.Normal;
            }

            List <Vector3> rectPoints = MathHelper.Transform(wcsPoints, newNormal, CoordinateSystem.World, CoordinateSystem.Object);

            // corners of the transformed rectangle that circumscribe the new ellipse
            Vector2 pointA = new Vector2(rectPoints[0].X, rectPoints[0].Y);
            Vector2 pointB = new Vector2(rectPoints[1].X, rectPoints[1].Y);
            Vector2 pointC = new Vector2(rectPoints[2].X, rectPoints[2].Y);
            Vector2 pointD = new Vector2(rectPoints[3].X, rectPoints[3].Y);

            // the new ellipse is tangent at the mid points
            Vector2 pointM = Vector2.MidPoint(pointA, pointB);
            Vector2 pointN = Vector2.MidPoint(pointC, pointD);
            Vector2 pointH = Vector2.MidPoint(pointA, pointC);
            Vector2 pointK = Vector2.MidPoint(pointB, pointD);

            // we need to find a fifth point
            Vector2 origin = Vector2.MidPoint(pointH, pointK);
            Vector2 pointX = Vector2.MidPoint(pointH, origin); // a point along the OH segment

            // intersection line AC and line parallel to BC through pointX
            Vector2 pointY = MathHelper.FindIntersection(pointA, pointC - pointA, pointX, pointC - pointB);

            if (Vector2.IsNaN(pointY))
            {
                Debug.Assert(false, "The transformation cannot be applied.");
                return;
            }

            // find the fifth point in the ellipse
            Vector2 pointZ = MathHelper.FindIntersection(pointM, pointX - pointM, pointN, pointY - pointN);

            if (Vector2.IsNaN(pointZ))
            {
                Debug.Assert(false, "The transformation cannot be applied.");
                return;
            }

            Vector3 oldNormal   = this.Normal;
            double  oldRotation = this.Rotation * MathHelper.DegToRad;

            if (ConicThroughFivePoints.EllipseProperties(pointM, pointN, pointH, pointK, pointZ, out Vector2 _, out double newSemiMajorAxis, out double newSemiMinorAxis, out double newRotation))
            {
                double axis1 = 2 * newSemiMajorAxis;
                axis1 = MathHelper.IsZero(axis1) ? MathHelper.Epsilon : axis1;
                double axis2 = 2 * newSemiMinorAxis;
                axis2 = MathHelper.IsZero(axis2) ? MathHelper.Epsilon : axis2;

                this.Center    = transformation * this.Center + translation;
                this.MajorAxis = axis1;
                this.MinorAxis = axis2;
                this.Rotation  = newRotation * MathHelper.RadToDeg;
                this.Normal    = newNormal;
            }
Exemplo n.º 2
0
        /// <summary>
        /// Moves, scales, and/or rotates the current entity given a 3x3 transformation matrix and a translation vector.
        /// </summary>
        /// <param name="transformation">Transformation matrix.</param>
        /// <param name="translation">Translation vector.</param>
        /// <remarks>Matrix3 adopts the convention of using column vectors to represent a transformation matrix.</remarks>
        public override void TransformBy(Matrix3 transformation, Vector3 translation)
        {
            // NOTE: this is a generic implementation of the ellipse transformation,
            // for non rotated ellipses and/or uniform scaling the code can be simplified

            // rectangle that circumscribe the ellipse
            double semiMajorAxis = this.MajorAxis * 0.5;
            double semiMinorAxis = this.MinorAxis * 0.5;

            Vector2        p1        = new Vector2(-semiMajorAxis, semiMinorAxis);
            Vector2        p2        = new Vector2(semiMajorAxis, semiMinorAxis);
            Vector2        p3        = new Vector2(-semiMajorAxis, -semiMinorAxis);
            Vector2        p4        = new Vector2(semiMajorAxis, -semiMinorAxis);
            List <Vector2> ocsPoints = MathHelper.Transform(new[] { p1, p2, p3, p4 }, this.Rotation * MathHelper.DegToRad, CoordinateSystem.Object, CoordinateSystem.World);

            Vector3        p1Prime   = new Vector3(ocsPoints[0].X, ocsPoints[0].Y, 0.0);
            Vector3        p2Prime   = new Vector3(ocsPoints[1].X, ocsPoints[1].Y, 0.0);
            Vector3        p3Prime   = new Vector3(ocsPoints[2].X, ocsPoints[2].Y, 0.0);
            Vector3        p4Prime   = new Vector3(ocsPoints[3].X, ocsPoints[3].Y, 0.0);
            List <Vector3> wcsPoints = MathHelper.Transform(new[] { p1Prime, p2Prime, p3Prime, p4Prime }, this.Normal, CoordinateSystem.Object, CoordinateSystem.World);

            for (int i = 0; i < wcsPoints.Count; i++)
            {
                wcsPoints[i] += this.Center;

                wcsPoints[i]  = transformation * wcsPoints[i];
                wcsPoints[i] += translation;
            }

            Vector3 newNormal = transformation * this.Normal;

            if (Vector3.Equals(Vector3.Zero, newNormal))
            {
                newNormal = this.Normal;
            }

            List <Vector3> rectPoints = MathHelper.Transform(wcsPoints, newNormal, CoordinateSystem.World, CoordinateSystem.Object);

            // corners of the transformed rectangle that circumscribe the new ellipse
            Vector2 pointA = new Vector2(rectPoints[0].X, rectPoints[0].Y);
            Vector2 pointB = new Vector2(rectPoints[1].X, rectPoints[1].Y);
            Vector2 pointC = new Vector2(rectPoints[2].X, rectPoints[2].Y);
            Vector2 pointD = new Vector2(rectPoints[3].X, rectPoints[3].Y);

            // the new ellipse is tangent at the mid points
            Vector2 pointM = Vector2.MidPoint(pointA, pointB);
            Vector2 pointN = Vector2.MidPoint(pointC, pointD);
            Vector2 pointH = Vector2.MidPoint(pointA, pointC);
            Vector2 pointK = Vector2.MidPoint(pointB, pointD);

            // we need to find a fifth point
            Vector2 origin = Vector2.MidPoint(pointH, pointK);
            Vector2 pointX = Vector2.MidPoint(pointH, origin); // a point along the OH segment

            // intersection line AC and line parallel to BC through pointX
            Vector2 pointY = MathHelper.FindIntersection(pointA, pointC - pointA, pointX, pointC - pointB);

            if (Vector2.IsNaN(pointY))
            {
                Debug.Assert(false, "The transformation cannot be applied.");
                return;
            }

            // find the fifth point in the ellipse
            Vector2 pointZ = MathHelper.FindIntersection(pointM, pointX - pointM, pointN, pointY - pointN);

            if (Vector2.IsNaN(pointZ))
            {
                Debug.Assert(false, "The transformation cannot be applied.");
                return;
            }

            Vector3 oldNormal   = this.Normal;
            double  oldRotation = this.Rotation;

            Vector2 newCenter;
            double  newSemiMajorAxis;
            double  newSemiMinorAxis;
            double  newRotation;

            if (ConicThroughFivePoints.EllipseProperties(pointM, pointN, pointH, pointK, pointZ, out newCenter, out newSemiMajorAxis, out newSemiMinorAxis, out newRotation))
            {
                double axis1 = 2 * newSemiMajorAxis;
                axis1 = MathHelper.IsZero(axis1) ? MathHelper.Epsilon : axis1;
                double axis2 = 2 * newSemiMinorAxis;
                axis2 = MathHelper.IsZero(axis2) ? MathHelper.Epsilon : axis2;

                this.Center    = transformation * this.Center + translation;
                this.MajorAxis = axis1;
                this.MinorAxis = axis2;
                this.Rotation  = newRotation * MathHelper.RadToDeg;
                this.Normal    = newNormal;
            }
            else
            {
                Debug.Assert(false, "The transformation cannot be applied.");
                return;
            }

            if (this.IsFullEllipse)
            {
                return;
            }

            //if not full ellipse calculate start and end angles
            Vector2 start = this.PolarCoordinateRelativeToCenter(this.StartAngle);
            Vector2 end   = this.PolarCoordinateRelativeToCenter(this.EndAngle);

            if (!MathHelper.IsZero(oldRotation))
            {
                double beta    = oldRotation * MathHelper.DegToRad;
                double sinBeta = Math.Sin(beta);
                double cosBeta = Math.Cos(beta);

                start = new Vector2(start.X * cosBeta - start.Y * sinBeta, start.X * sinBeta + start.Y * cosBeta);
                end   = new Vector2(end.X * cosBeta - end.Y * sinBeta, end.X * sinBeta + end.Y * cosBeta);
            }

            Vector3 pStart = new Vector3(start.X, start.Y, 0.0);
            Vector3 pEnd   = new Vector3(end.X, end.Y, 0.0);

            List <Vector3> wcsAnglePoints = MathHelper.Transform(new[] { pStart, pEnd }, oldNormal, CoordinateSystem.Object, CoordinateSystem.World);

            for (int i = 0; i < wcsAnglePoints.Count; i++)
            {
                wcsPoints[i] += this.Center;

                wcsAnglePoints[i] = transformation * wcsAnglePoints[i];
                wcsPoints[i]     += translation;
            }

            List <Vector3> ocsAnglePoints = MathHelper.Transform(wcsAnglePoints, newNormal, CoordinateSystem.World, CoordinateSystem.Object);

            Vector2 newStart = new Vector2(ocsAnglePoints[0].X, ocsAnglePoints[0].Y);
            Vector2 newEnd   = new Vector2(ocsAnglePoints[1].X, ocsAnglePoints[1].Y);

            double invert = Math.Sign(transformation.M11 * transformation.M22 * transformation.M33) < 0 ? 180.0 : 0.0;

            this.StartAngle = invert + Vector2.Angle(newStart) * MathHelper.RadToDeg - this.Rotation;
            this.EndAngle   = invert + Vector2.Angle(newEnd) * MathHelper.RadToDeg - this.Rotation;
        }