예제 #1
0
        /// <summary>
        /// Gets the intersection point coordinate between the current plane and another specified plane.
        /// </summary>
        /// <param name="p">Plane that should cross the plane on the seeked intersection line.</param>
        /// <returns>The parametric line at the intersection between the 2 planes.</returns>
        /// <remarks>
        /// Formula :
        ///
        /// A(x1 + at) + B(y1 + bt) + C(z1 + ct) + D = 0
        ///
        /// Then giving t :
        ///
        ///      -(Ax1 + By1 + Cz1 + D)
        /// t = ------------------------
        ///           Aa + Bb + Cc
        ///
        /// Coordinates are then :
        ///
        ///           a(Ax1 + By1 + Cz1 + D)             b(Ax1 + By1 + Cz1 + D)             c(Ax1 + By1 + Cz1 + D)
        /// x = x1 - ------------------------  y = y1 - ------------------------  z = z1 - ------------------------
        ///                Aa + Bb + Cc                       Aa + Bb + Cc                       Aa + Bb + Cc
        ///
        /// </remarks>
        public ParametricLine GetIntersection(Plane p)
        {
            // Orientation of the intersection between the plane is a vector perpendicular to the normals of both planes.
            Cartesian3dCoordinate orientation = this.Normal.CrossProduct(p.Normal);

            // Base on the plane equation, we need to adapt to use the correct resolution to avoid usses coming from potential divide by 0.0.
            Cartesian3dCoordinate point;

            if (TryGetPointAtIntersectionOnZ(p, out Cartesian3dCoordinate rZ))
            {
                point = rZ;
            }
            else if (TryGetPointAtIntersectionOnY(p, out Cartesian3dCoordinate rY))
            {
                point = rY;
            }
            else if (TryGetPointAtIntersectionOnX(p, out Cartesian3dCoordinate rX))
            {
                point = rX;
            }
            else
            {
                throw new NotImplementedException("The method was not able to find a way to get the intersection between the 2 Plane with the currently implemented formula.");
            }

            return(new ParametricLine(point, orientation));
        }
 /// <summary>
 /// Gets the Cross Product between this vector and another vector.
 /// </summary>
 /// <param name="v">Vector with which we will calculate the cross product.</param>
 /// <returns>New coordinates containing the cross product from the 2 vectors.</returns>
 public Cartesian3dCoordinate CrossProduct(Cartesian3dCoordinate v)
 {
     return(new Cartesian3dCoordinate(
                (this.Y * v.Z) - (this.Z * v.Y),
                (this.Z * v.X) - (this.X * v.Z),
                (this.X * v.Y) - (this.Y * v.X)
                ));
 }
예제 #3
0
        /// <summary>
        /// Create a new plane based on his normal and a random point that is part of the plane.
        /// </summary>
        /// <param name="normal">Vector of the normal to the plane. The normal is a perpendicular vector to the plane.</param>
        /// <param name="point">Point included in the plane and not included in the normal.</param>
        public Plane(Cartesian3dCoordinate normal, Cartesian3dCoordinate point)
        {
            this.Normal = normal;

            // As : 0 = ax + by + cz + d
            //      -d = ax + by + cz
            //      d = -(ax + by + cz)
            this.D = -((normal.X * point.X) + (normal.Y * point.Y) + (normal.Z * point.Z));
        }
예제 #4
0
 /// <summary>
 /// Convert a Cartesian Point to his Homogeneous equivalent.
 /// </summary>
 /// <param name="cc">Cartesian coordinate to convert.</param>
 /// <returns>The Vector converted to a Homogeneous representation.</returns>
 public static HomogeneousCoordinate ConvertToHomogeneous(Cartesian3dCoordinate cc)
 {
     return(new HomogeneousCoordinate(
                cc.X,
                cc.Y,
                cc.Z,
                1.0
                ));
 }
예제 #5
0
        /// <summary>
        /// Try to calculate a point at the intersection of 2 plane using linear combination.
        /// As we only have 2 plane to find a point, the Z value is predefined to 0.0.
        /// </summary>
        /// <param name="p">Second Plane with which we search the intersection point.</param>
        /// <param name="cc">Calculated coordinate of one of the intersection point between the 2 Planes in case of success.</param>
        /// <returns>A boolean indicating whther this function was able to evaluate the expected point or not.</returns>
        private bool TryGetPointAtIntersectionOnZ(Plane p, out Cartesian3dCoordinate cc)
        {
            // Avoid to divide by 0.0 at the end. (see last formula)
            if (this.B.IsZero())
            {
                cc = Cartesian3dCoordinate.Zero;
                return(false);
            }

            // We have 2 formula with 3 variables :
            // A1 X + B1 Y + C1 Z + D1 = 0
            // A2 X + B2 Y + C2 Z + D2 = 0
            //
            // We will limit equations to 2 variables by predefining Z to 0.0 :
            // A1 X + B1 Y = -D1
            // A2 X + B2 Y = -D2
            //
            // We will then use linear combination between the 2 formulas :
            // A1 X B2 + B1 Y B2 = -D1 B2
            // A2 X B1 + B2 Y B1 = -D2 B1
            //
            // B1 Y B2 = -D1 B2 - A1 X B2
            // B2 Y B1 = -D2 B1 - A2 X B1
            //
            // This give us :
            //
            // A2 X B1 - A1 X B2 = D1 B2 - D2 B1
            //
            // (A2 B1 - A1 B2) X = D1 B2 - D2 B1
            //
            //      D1 B2 - D2 B1
            // X = ---------------
            //      A2 B1 - A1 B2
            double divisor = (p.A * this.B) - (this.A * p.B);

            if (divisor.IsZero())
            {
                cc = Cartesian3dCoordinate.Zero;
                return(false);
            }

            double x = ((this.D * p.B) - (p.D * this.B)) / divisor;

            // With this X calculated and Z to 0.0, we can then resolve one of the equations for Y :
            //
            //        A1 X + D1
            // Y = - -----------
            //           B1
            cc = new Cartesian3dCoordinate(
                x,
                -((this.A * x) + this.D) / this.B,
                0.0
                );

            return(true);
        }
        /// <summary>
        /// Get the vector corresponding to this vector in the current referential as if this vector was related to another referential vector.
        /// </summary>
        /// <param name="referential">Vector correspoding to the X axis vector in the referential coordinates.</param>
        /// <returns>A new coordinates sets in the global coordinates system corresponding to the translated coordinates.</returns>
        /// <remarks>
        /// Assuming a transposition of A on B.
        ///
        /// Let V = a X b
        /// Let s = ||V|| (sin of angle)
        /// Let c = A . B (cos of angle)
        ///
        /// Rotation matrix can be calculated by:
        ///
        /// R = I + [V]x + [V]ײ (1 − c) / s²
        ///
        /// As a reminder:
        ///
        ///        (  0  -Vz  Vy )         ( 1 0 0 )               (  1  -Vz  Vy )
        /// [V]x = (  Vz  0  -Vx )     I = ( 0 1 0 )    [V]x + I = (  Vz  1  -Vx )
        ///        ( -Vy  Vx  0  )         ( 0 0 1 )               ( -Vy  Vx  1  )
        /// </remarks>
        public Cartesian3dCoordinate TransposeFromReferential(Cartesian3dCoordinate referential)
        {
            if (referential.IsOnX)
            {
                if (referential.X > 0.0)
                {
                    // No need to change referential when we are on the correct one.
                    return(this);
                }
                else
                {
                    // Formula is not working for reverse referential vector, we just reverse the current coordinates.
                    return(new Cartesian3dCoordinate(-this.X, -this.Y, -this.Z));
                }
            }

            Cartesian3dCoordinate origin = new Cartesian3dCoordinate(1, 0, 0);

            // Calculate formula variables.
            Cartesian3dCoordinate v = origin.CrossProduct(referential);
            double c = origin.DotProduct(referential);

            // Calculate last part.
            double cPart = (1.0 - c) / ((v.X * v.X) + (v.Y * v.Y) + (v.Z * v.Z));

            // Calculate poer values.
            double x2 = v.X * v.X;
            double y2 = v.Y * v.Y;
            double z2 = v.Z * v.Z;

            // Calculate the rotation matrix
            double[,] matrix = new double[3, 3]
            {
                {
                    1.0 - ((z2 + y2) * cPart),
                    (v.Y * -v.X * cPart) - v.Z,
                    (v.Z * v.X * cPart) + v.Y,
                },
                {
                    (v.X * v.Y * cPart) + v.Z,
                    1.0 - ((z2 + x2) * cPart),
                    (v.Z * v.Y * cPart) - v.X,
                },
                {
                    (v.X * v.Z * cPart) - v.Y,
                    (v.Y * v.Z * cPart) + v.X,
                    1.0 - ((y2 + x2) * cPart),
                },
            };

            // Apply rotation matrix to vector.
            return(new Cartesian3dCoordinate(
                       (this.X * matrix[0, 0]) + (this.Y * matrix[0, 1]) + (this.Z * matrix[0, 2]),
                       (this.X * matrix[1, 0]) + (this.Y * matrix[1, 1]) + (this.Z * matrix[1, 2]),
                       (this.X * matrix[2, 0]) + (this.Y * matrix[2, 1]) + (this.Z * matrix[2, 2])));
        }
예제 #7
0
        /// <summary>
        /// Try to calculate a point at the intersection of 2 plane using linear combination.
        /// As we only have 2 plane to find a point, the X value is predefined to 0.0.
        /// </summary>
        /// <param name="p">Second Plane with which we search the intersection point.</param>
        /// <returns>Coordinate of one of the intersection point between the 2 Planes.</returns>
        private bool TryGetPointAtIntersectionOnX(Plane p, out Cartesian3dCoordinate cc)
        {
            // Avoid to divide by 0.0 at the end. (see last formula)
            if (this.C.IsZero())
            {
                cc = Cartesian3dCoordinate.Zero;
                return(false);
            }

            // We have 2 formula with 3 variables :
            // A1 X + B1 Y + C1 Z + D1 = 0
            // A2 X + B2 Y + C2 Z + D2 = 0
            //
            // We will limit equations to 2 variables by predefining X to 0.0 :
            // B1 Y + C1 Z = -D1
            // B2 Y + C2 Z = -D2
            //
            // We will then use linear combination between the 2 formulas :
            // B1 Y C2 + C1 Z C2 = -D1 C2
            // B2 Y C1 + C2 Z C1 = -D2 C1
            //
            // C1 Z C2 = -D1 C2 - B1 Y C2
            // C2 Z C1 = -D2 C1 - B2 Y C1
            //
            // This give us :
            //
            // B2 Y C1 - B1 Y C2 = D1 C2 - D2 C1
            //
            // (B2 C1 - B1 C2) Y = D1 C2 - D2 C1
            //
            //      D1 C2 - D2 C1
            // Y = ---------------
            //      B2 C1 - B1 C2
            double divisor = (p.B * this.C) - (this.B * p.C);

            if (divisor.IsZero())
            {
                cc = Cartesian3dCoordinate.Zero;
                return(false);
            }

            double y = ((this.D * p.C) - (p.D * this.C)) / divisor;

            // With this Y calculated and X to 0.0, we can then resolve one of the equations for Z :
            //
            //        B1 Y + D1
            // Z = - -----------
            //           C1
            cc = new Cartesian3dCoordinate(
                0.0,
                y,
                -((this.B * y) + this.D) / this.C
                );

            return(true);
        }
예제 #8
0
        /// <summary>
        /// Gets the 2D coordinates as seen from a calculated plane.
        /// </summary>
        /// <param name="cc">3D coordinates to convert.</param>
        /// <returns>The converted 2D coordinates.</returns>
        private Cartesian2dCoordinate GetFromProjection(Cartesian3dCoordinate cc)
        {
            // Project the coordinates on the reference
            ParametricLine        projectionLine  = this.Plane.GetPerpendicular(cc);
            Cartesian3dCoordinate planeCoordinate = this.Plane.GetIntersection(projectionLine);

            Cartesian3dCoordinate ccOnX = planeCoordinate.TransposeFromReferential(this.Plane.Normal);

            return(GetFromFront(ccOnX));
        }
        /// <summary>
        /// Create a new vector resulting from a rotation around a specific axis using the rodrigues' formula.
        /// </summary>
        /// <param name="k">Vector used as the rotation axis.</param>
        /// <param name="theta">Angle fo rotation to execute in radians.</param>
        /// <returns>The coordinates of the rotated vector.</returns>
        /// <remarks>
        /// Rotation formula :
        ///
        ///	 V : This vector.
        ///	 K : Vector used a rotation axis.
        ///
        ///  R = V cos theta + (K × V) sin theta + K (K . V) (1 − cos theta)
        /// </remarks>
        public Cartesian3dCoordinate RotateAroundVector(Cartesian3dCoordinate k, double theta)
        {
            // Precalculate intermediates values used more than once.
            double cosTheta = Trigonometry.Cos(theta);
            double sinTheta = Trigonometry.Sin(theta);

            k = k.Normalize();

            return((this * cosTheta) + ((-sinTheta) * CrossProduct(k)) + ((1.0 - cosTheta) * this.DotProduct(k) * k));
        }
        /// <summary>
        /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
        /// </summary>
        /// <param name="x">The first object to compare.</param>
        /// <param name="y">The second object to compare.</param>
        /// <returns>
        /// A signed integer that indicates the relative values of x and y:
        /// - If less than 0, x is less than y.
        /// - If 0, x equals y.
        /// - If greater than 0, x is greater than y.
        /// </returns>
        public int Compare(Cartesian3dCoordinate x, Cartesian3dCoordinate y)
        {
            // Check perfect equality first to avoid further calculations.
            if (x.IsSamePoint(y))
            {
                return(0);
            }

            Cartesian2dCoordinate x2 = m_Converter.ConvertTo2d(x);
            Cartesian2dCoordinate y2 = m_Converter.ConvertTo2d(y);

            return(Compare(x2, y2));
        }
예제 #11
0
        /// <summary>
        /// Convert a Cartesian Vector to his Spherical equivalent.
        /// </summary>
        /// <param name="cc">Cartesian coordinate to convert.</param>
        /// <returns>The Vector converted to a Spherical representation.</returns>
        public static SphericalVector ConvertToSpherical(Cartesian3dCoordinate cc)
        {
            // Pre validate value to avoid double.NaN in calculation result.
            if (cc.IsZero)
            {
                return(SphericalVector.Origin);
            }

            return(new SphericalVector(
                       Math.Atan2(cc.Y, cc.X),
                       Trigonometry.Acos(cc.Z / cc.Magnitude)
                       ));
        }
예제 #12
0
        /// <summary>
        /// Gets the intersection point coordinate between the current plane and the specified Vector.
        /// </summary>
        /// <param name="v">Vector that should cross the plane at the seeked intersection point.</param>
        /// <returns>The cartesian coordinates of the intersection point between the Vector and the Plane.</returns>
        /// <remarks>
        /// This is a simplified version of the formula from the ParametricLine formula.
        /// All part of the formula known as been equals to 0 are not calculated.
        /// </remarks>
        public Cartesian3dCoordinate GetIntersection(Cartesian3dCoordinate v)
        {
            double divisor = GetSumOfAbcProduct(v);

            if (divisor.IsZero())
            {
                throw new InvalidOperationException("Cannot Get Intersection between a Plane and a parallel vector.");
            }

            double planePart = -this.D / divisor;

            return(new Cartesian3dCoordinate(
                       v.X * planePart,
                       v.Y * planePart,
                       v.Z * planePart
                       ));
        }
예제 #13
0
 /// <summary>
 /// Gets the dot product between this vector in a 1 X 3 format and a second one in a 3 X 1 format.
 /// </summary>
 /// <param name="c">Vector that will be used as a 3 X 1 matrix.</param>
 /// <returns>Calculated vector from the dot product of the 2 vectors.</returns>
 public double DotProduct(Cartesian3dCoordinate c)
 {
     return((this.X * c.X) + (this.Y * c.Y) + (this.Z * c.Z));
 }
예제 #14
0
 /// <summary>
 /// Calculate the theta angle relative to a provided vector.
 /// </summary>
 /// <param name="x">Vector that will be used to calculate the theta</param>
 /// <returns>Calculated theta value between the two vectors.</returns>
 /// <remarks>
 /// Formula :
 ///
 ///  V : This vector.
 ///  X : Vector to which the angle theta is calculated.
 ///
 ///                  V . X
 ///  cos theta = -------------
 ///               ||X|| ||Y||
 /// </remarks>
 public double GetThetaTo(Cartesian3dCoordinate x)
 {
     return(Trigonometry.Acos(this.DotProduct(x) / (this.Magnitude * x.Magnitude)));
 }
예제 #15
0
 /// <summary>
 /// Gets a ParametricLine perpendicular to the plane and passing through a provided point.
 /// </summary>
 /// <param name="point">Point through which the perpendicular line to the plane should go.</param>
 /// <returns>A new line going through the provided point and the current plane.</returns>
 public ParametricLine GetPerpendicular(Cartesian3dCoordinate point) => new ParametricLine(point, this.Normal);
예제 #16
0
 /// <summary>
 /// Gets the sum of products of the A, B and C factor of the plane and vector formula.
 /// </summary>
 /// <param name="cc">Parametric line with which we calculate the product.</param>
 /// <returns>Result of the sum of the product of the A, B and C factor of the plane and parametric line formula.</returns>
 private double GetSumOfAbcProduct(Cartesian3dCoordinate cc) => (this.A * cc.X) + (this.B * cc.Y) + (this.C * cc.Z);
예제 #17
0
 /// <summary>
 /// Create a ParametricLine between 2 lines.
 /// </summary>
 /// <param name="p1">Starting point of the line.</param>
 /// <param name="p2">Ending point of the line.</param>
 /// <returns>The Parametric line linking the provided points.</returns>
 public static ParametricLine FromTwoPoints(Cartesian3dCoordinate p1, Cartesian3dCoordinate p2)
 {
     return(new ParametricLine(p1, new Cartesian3dCoordinate(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z)));
 }
예제 #18
0
 /// <summary>
 /// Gets the 2D coordinates as seen from the top.
 /// </summary>
 /// <param name="cc">3D coordinates to convert.</param>
 /// <returns>The converted 2D coordinates.</returns>
 private Cartesian2dCoordinate GetFromTop(Cartesian3dCoordinate cc) => new Cartesian2dCoordinate(cc.Y, -cc.X);
예제 #19
0
        /// <summary>
        /// Indicate if a specific point is above the plane or not.
        /// </summary>
        /// <param name="point">Point for which position relative to the plane will be checked.</param>
        /// <returns>A boolean indicating whether the point is above the plane or not.</returns>
        /// <remarks>Formula : ax + by + cz + d = 0</remarks>
        public bool IsAbovePlane(Cartesian3dCoordinate point)
        {
            double v = GetSumOfAbcProduct(point) + this.D;

            return(!v.IsZero() && v > 0.0);
        }
예제 #20
0
 /// <summary>
 /// Gets the 2D coordinates as seen from the left.
 /// </summary>
 /// <param name="cc">3D coordinates to convert.</param>
 /// <returns>The converted 2D coordinates.</returns>
 private Cartesian2dCoordinate GetFromLeft(Cartesian3dCoordinate cc) => new Cartesian2dCoordinate(cc.X, cc.Z);
예제 #21
0
 /// <summary>
 /// Gets the 2D coordinates as seen from the right.
 /// </summary>
 /// <param name="cc">3D coordinates to convert.</param>
 /// <returns>The converted 2D coordinates.</returns>
 private Cartesian2dCoordinate GetFromRight(Cartesian3dCoordinate cc) => new Cartesian2dCoordinate(-cc.X, cc.Z);
예제 #22
0
 /// <summary>
 /// Gets the 2D coordinates as seen from the back.
 /// </summary>
 /// <param name="cc">3D coordinates to convert.</param>
 /// <returns>The converted 2D coordinates.</returns>
 private Cartesian2dCoordinate GetFromBack(Cartesian3dCoordinate cc) => new Cartesian2dCoordinate(-cc.Y, cc.Z);
예제 #23
0
 /// <summary>
 /// Evaluate if the 2 Cartesian3dCoordinate are concidered as equal points in this context.
 /// </summary>
 /// <param name="cc">Coordinates to compare to the current object.</param>
 /// <returns>A boolean indicating whether the 2 coordinates are equals or not.</returns>
 public bool IsSamePoint(Cartesian3dCoordinate cc) => this.X.IsEqualTo(cc.X) && this.Y.IsEqualTo(cc.Y) && this.Z.IsEqualTo(cc.Z);
예제 #24
0
 /// <summary>
 /// Gets the 2D coordinates as seen from the bottom.
 /// </summary>
 /// <param name="cc">3D coordinates to convert.</param>
 /// <returns>The converted 2D coordinates.</returns>
 private Cartesian2dCoordinate GetFromBottom(Cartesian3dCoordinate cc) => new Cartesian2dCoordinate(cc.Y, cc.X);
예제 #25
0
 /// <summary>
 /// Evaluate if the 2 Cartesian3dCoordinate are concidered as equal vector in this context.
 /// </summary>
 /// <param name="cc">Coordinates to compare to the current object.</param>
 /// <returns>A boolean indicating whether the 2 coordinates are equals or not.</returns>
 public bool IsSameVector(Cartesian3dCoordinate cc) => this.Normalize().IsSamePoint(cc.Normalize());
예제 #26
0
 /// <summary>
 /// Gets the 2D coordinates as seen from the front.
 /// </summary>
 /// <param name="cc">3D coordinates to convert.</param>
 /// <returns>The converted 2D coordinates.</returns>
 private Cartesian2dCoordinate GetFromFront(Cartesian3dCoordinate cc) => new Cartesian2dCoordinate(cc.Y, cc.Z);
예제 #27
0
 /// <summary>
 /// Create a ParametricLine starting from a specific point and following a provided Vector.
 /// </summary>
 /// <param name="p">Initial point of the line.</param>
 /// <param name="v">Vector providing the direction of the line.</param
 public ParametricLine(Cartesian3dCoordinate p, Cartesian3dCoordinate v)
 {
     this.Point  = p;
     this.Vector = v;
 }
예제 #28
0
 /// <summary>
 /// Create a new Plane.
 /// </summary>
 /// <param name="n">Normal used to define a plane.</param>
 /// <param name="d">D factor of the formula 'ax + by + cz + d = 0' used to define a plane.</param>
 public Plane(Cartesian3dCoordinate n, double d)
 {
     this.Normal = n;
     this.D      = d;
 }
예제 #29
0
 /// <summary>
 /// COnvert the provided 3D coordiantes to their projected 2D counterpart on the Plane used to create this Cartesian3dCoordinatesConverter.
 /// </summary>
 /// <param name="c3d">2D coordinates to project on the Pland and converts in 2D.</param>
 /// <returns>2D coordinates projectes on the Plane.</returns>
 public Cartesian2dCoordinate ConvertTo2d(Cartesian3dCoordinate c3d) => m_From3dTo2d(c3d);
예제 #30
0
 /// <summary>
 /// Indicate if a specific point is on the plane or not.
 /// </summary>
 /// <param name="point">Point for which appartenance to the plane will be checked.</param>
 /// <returns>A boolean indicating whether the point is ont the plane or not.</returns>
 /// <remarks>Formula : ax + by + cz + d = 0</remarks>
 public bool IsOnPlane(Cartesian3dCoordinate point) => (GetSumOfAbcProduct(point) + this.D).IsZero();