/// <summary>
        /// Computes the depth values of a given floor and ceiling in pixel space
        /// </summary>
        /// <param name="cameraPose">The camera pose</param>
        /// <param name="floorThreshold">The floor threshold</param>
        /// <param name="ceilingThreshold">The ceiling threshold</param>
        /// <param name="invProjectionMatrix">The inverse projection matrix</param>
        /// <param name="floorCeilingMinDepths">The computed min depths of floor and ceiling</param>
        /// <param name="floorCeilingMaxDepths">The computed max depths of floor and ceiling</param>
        /// <param name="width">Width of the image</param>
        /// <param name="height">Height of the image</param>
        /// <param name="depthRange">Depth range of the camera</param>
        public static void ComputeCeilingAndFloorDepthsInPixelSpace(
            Pose cameraPose,
            float floorThreshold,
            float ceilingThreshold,
            Microsoft.Robotics.PhysicalModel.Matrix invProjectionMatrix,
            ref short[] floorCeilingMinDepths,
            ref short[] floorCeilingMaxDepths,
            int width,
            int height,
            float depthRange)
        {
            floorCeilingMinDepths = new short[width * height];
            floorCeilingMaxDepths = new short[width * height];

            ComputeCeilingAndFloorDepthsInPixelSpaceInternal(
                ref cameraPose,
                floorThreshold,
                ceilingThreshold,
                ref invProjectionMatrix,
                floorCeilingMinDepths,
                floorCeilingMaxDepths,
                width,
                height,
                depthRange);
        }
 /// <summary>
 /// Computes projection matrix from width, height, fov and caches inverse
 /// </summary>
 private void UpdateProjectionMatrix()
 {
     if (this.Width != 0 && this.Height != 0 && this.HorizontalFieldOfView != 0)
     {
         this.ProjectionMatrix = MathUtilities.ComputeProjectionMatrix(
             (float)this.HorizontalFieldOfView,
             this.Width,
             this.Height,
             10);
         this.InverseProjectionMatrix = MathUtilities.Invert(this.ProjectionMatrix);
     }
 }
        /// <summary>
        /// Converts a coordinate in screen space to a vector in view space in millimeters
        /// Allows for working in the native resolution of the depth camera with less conversions
        /// </summary>
        /// <param name="x">X-coordinate with range [0, screenWidth-1]</param>
        /// <param name="y">Y-coordinate with range [0, screenHeight-1]</param>
        /// <param name="z">Z-coordinate with range [0, maxValidDepth] in mm</param>
        /// <param name="invProjectionMatrix">Inverse projection matrix of the camera</param>
        /// <param name="screenWidth">Width of the camera view plane in pixel space</param>
        /// <param name="screenHeight">Height of the camera view plane in pixel space</param>
        /// <returns>Viewspace vector with depth in millimeters</returns>
        public static Vector3 ConvertPixelSpaceToViewSpaceInMillimeters(
            int x,
            int y,
            int z,
            Microsoft.Robotics.PhysicalModel.Matrix invProjectionMatrix,
            int screenWidth,
            int screenHeight)
        {
            var positionInMeters = ConvertPixelSpaceToViewSpace(x, y, z, invProjectionMatrix, screenWidth, screenHeight);

            // multiply by 1000 to convert to millimeters
            return(Vector3.Scale(positionInMeters, 1000.0f));
        }
        /// <summary>
        /// Converts a vector in view space to a vector in screen space
        /// </summary>
        /// <param name="viewSpaceVector">View space vector</param>
        /// <param name="projectionMatrix">Projection matrix</param>
        /// <param name="screenWidth">Screen width</param>
        /// <param name="screenHeight">Screen height</param>
        /// <returns>Pixel space vector</returns>
        public static Vector3 ConvertViewSpaceToPixelSpaceWithDepthInMillimeters(
            Vector3 viewSpaceVector,
            Microsoft.Robotics.PhysicalModel.Matrix projectionMatrix,
            int screenWidth,
            int screenHeight)
        {
            var screenSpacePoint = ConvertViewSpaceToPixelSpace(ref viewSpaceVector, ref projectionMatrix, screenWidth, screenHeight);

            // we return 'z' in millimeters as that is the unit z is returned from the camera
            return(new Vector3(
                       screenSpacePoint.X,
                       screenSpacePoint.Y,
                       viewSpaceVector.Z * 1000.0f));
        }
        /// <summary>
        /// Converts a coordinate in screen space to a vector in view space
        /// </summary>
        /// <param name="x">X-coordinate with range [0, screenWidth-1]</param>
        /// <param name="y">Y-coordinate with range [0, screenHeight-1]</param>
        /// <param name="z">Z-coordinate with range [0, maxValidDepth] in mm</param>
        /// <param name="invProjectionMatrix">Inverse projection matrix of the camera</param>
        /// <param name="screenWidth">Width of the camera view plane in pixel space</param>
        /// <param name="screenHeight">Height of the camera view plane in pixel space</param>
        /// <returns>Viewspace vector</returns>
        public static Vector3 ConvertPixelSpaceToViewSpace(
            int x,
            int y,
            int z,
            Microsoft.Robotics.PhysicalModel.Matrix invProjectionMatrix,
            int screenWidth,
            int screenHeight)
        {
            float matrixAx, matrixBx, matrixAy, matrixBy;

            ComputeTranslationScaleTransform(screenWidth, screenHeight, out matrixAx, out matrixBx, out matrixAy, out matrixBy);

            return(ConvertPixelSpaceToViewSpace(x, y, z, invProjectionMatrix, screenWidth, matrixAx, matrixBx, matrixAy, matrixBy));
        }
        /// <summary>
        /// Converts a vector in view space to a vector in screen space
        /// </summary>
        /// <param name="viewSpaceVector">View space vector</param>
        /// <param name="projectionMatrix">Projection matrix</param>
        /// <param name="screenWidth">Screen width</param>
        /// <param name="screenHeight">Screen height</param>
        /// <returns>Pixel space vector</returns>
        private static Vector3 ConvertViewSpaceToPixelSpace(
            ref Vector3 viewSpaceVector,
            ref Microsoft.Robotics.PhysicalModel.Matrix projectionMatrix,
            int screenWidth,
            int screenHeight)
        {
            Vector4 ptW = TransformVector(
                new Vector4(viewSpaceVector.X, viewSpaceVector.Y, viewSpaceVector.Z, 1.0f),
                projectionMatrix);

            // project to screen space
            var screenSpacePoint = new Vector3(ptW.X / ptW.W, ptW.Y / ptW.W, ptW.Z / ptW.W);

            float w = (float)screenWidth, h = (float)screenHeight;
            float matrixAx = w * 0.5f, matrixBx = (w * 0.5f) - 0.5f;
            float matrixAy = -h * 0.5f, matrixBy = (h * 0.5f) - 0.5f;

            screenSpacePoint.X = (matrixAx * screenSpacePoint.X) + matrixBx + 0.5f;
            screenSpacePoint.Y = (matrixAy * screenSpacePoint.Y) + matrixBy + 0.5f;
            return(screenSpacePoint);
        }
        /// <summary>
        /// Inverts matrix
        /// </summary>
        /// <param name="matrix">Matrix to invert</param>
        /// <returns>Inverted matrix</returns>
        private static Microsoft.Robotics.PhysicalModel.Matrix InvertInternal(ref pm.Matrix matrix)
        {
            pm.Matrix matrix2;
            float     num5  = matrix.M11;
            float     num4  = matrix.M12;
            float     num3  = matrix.M13;
            float     num2  = matrix.M14;
            float     num9  = matrix.M21;
            float     num8  = matrix.M22;
            float     num7  = matrix.M23;
            float     num6  = matrix.M24;
            float     num17 = matrix.M31;
            float     num16 = matrix.M32;
            float     num15 = matrix.M33;
            float     num14 = matrix.M34;
            float     num13 = matrix.M41;
            float     num12 = matrix.M42;
            float     num11 = matrix.M43;
            float     num10 = matrix.M44;
            float     num23 = (num15 * num10) - (num14 * num11);
            float     num22 = (num16 * num10) - (num14 * num12);
            float     num21 = (num16 * num11) - (num15 * num12);
            float     num20 = (num17 * num10) - (num14 * num13);
            float     num19 = (num17 * num11) - (num15 * num13);
            float     num18 = (num17 * num12) - (num16 * num13);
            float     num39 = ((num8 * num23) - (num7 * num22)) + (num6 * num21);
            float     num38 = -(((num9 * num23) - (num7 * num20)) + (num6 * num19));
            float     num37 = ((num9 * num22) - (num8 * num20)) + (num6 * num18);
            float     num36 = -(((num9 * num21) - (num8 * num19)) + (num7 * num18));
            float     num   = 1f / ((((num5 * num39) + (num4 * num38)) + (num3 * num37)) + (num2 * num36));

            matrix2.M11 = num39 * num;
            matrix2.M21 = num38 * num;
            matrix2.M31 = num37 * num;
            matrix2.M41 = num36 * num;
            matrix2.M12 = -(((num4 * num23) - (num3 * num22)) + (num2 * num21)) * num;
            matrix2.M22 = (((num5 * num23) - (num3 * num20)) + (num2 * num19)) * num;
            matrix2.M32 = -(((num5 * num22) - (num4 * num20)) + (num2 * num18)) * num;
            matrix2.M42 = (((num5 * num21) - (num4 * num19)) + (num3 * num18)) * num;
            float num35 = (num7 * num10) - (num6 * num11);
            float num34 = (num8 * num10) - (num6 * num12);
            float num33 = (num8 * num11) - (num7 * num12);
            float num32 = (num9 * num10) - (num6 * num13);
            float num31 = (num9 * num11) - (num7 * num13);
            float num30 = (num9 * num12) - (num8 * num13);

            matrix2.M13 = (((num4 * num35) - (num3 * num34)) + (num2 * num33)) * num;
            matrix2.M23 = -(((num5 * num35) - (num3 * num32)) + (num2 * num31)) * num;
            matrix2.M33 = (((num5 * num34) - (num4 * num32)) + (num2 * num30)) * num;
            matrix2.M43 = -(((num5 * num33) - (num4 * num31)) + (num3 * num30)) * num;
            float num29 = (num7 * num14) - (num6 * num15);
            float num28 = (num8 * num14) - (num6 * num16);
            float num27 = (num8 * num15) - (num7 * num16);
            float num26 = (num9 * num14) - (num6 * num17);
            float num25 = (num9 * num15) - (num7 * num17);
            float num24 = (num9 * num16) - (num8 * num17);

            matrix2.M14 = -(((num4 * num29) - (num3 * num28)) + (num2 * num27)) * num;
            matrix2.M24 = (((num5 * num29) - (num3 * num26)) + (num2 * num25)) * num;
            matrix2.M34 = -(((num5 * num28) - (num4 * num26)) + (num2 * num24)) * num;
            matrix2.M44 = (((num5 * num27) - (num4 * num25)) + (num3 * num24)) * num;
            return(matrix2);
        }
 /// <summary>
 /// Matrix inversion from reflector since I don't feel like rewriting myself at the moment
 /// </summary>
 /// <param name="matrix">Matrix to invert</param>
 /// <returns>Inverted matrix</returns>
 public static pm.Matrix Invert(pm.Matrix matrix)
 {
     return(InvertInternal(ref matrix));
 }