-1

我有一个非常简单的方法,可以在给定测试点的线上找到最近的点。这是通过将vectorA投影到vectorB上来实现的,这样:

点测试点

VectorA = testPoint - 原点 VectorB

矢量C = (矢量A * 矢量B / |矢量B|^2)矢量B

如下图所示:

在此处输入图像描述

我遇到的问题是,在某些情况下,投影点不在线上。我如何在我的方法中保证这种行为?

        /// <summary>
        /// Returns the dot product of two vectors 
        /// This value equals vecA.Magnitude * vecB.Magnitude * cos(theta), where theta is the angle between both vectors.
        /// </summary>
        /// <param name="vecA"></param>
        /// <param name="VecB"></param>
        /// <returns></returns>
        public static double DotProduct(Vec3 vecA, Vec3 VecB)
        {
            return vecA.X * VecB.X + vecA.Y * VecB.Y + vecA.Z * VecB.Z;
        }


        /// <summary>
        /// Projection of vecA on to vecB
        /// </summary>
        /// <param name="vecA"></param>
        /// <param name="vecB"></param>
        /// <returns></returns>
        public static Vec3 Project(Vec3 vecA, Vec3 vecB)
        {
            return DotProduct(vecA, vecB) / vecB.SqrMagnitude * vecB;
        }



   /// <summary>
    /// Finds the closest point on a vector given a test point
    /// </summary>
    /// <param name="testPoint"></param>
    /// <param name="startVertex"></param>
    /// <param name="segment"></param>
    /// <returns></returns>
  public  static Vec3 VectorClosestPoint(Vec3 testPoint, Vec3 startVertex,Vec3 segment)
        {

            Vec3 b = testPoint - startVertex;
            Vec3 proj = Project(b, segment);
            Vec3 onCurve = startVertex + proj;

            return onCurve;


        }

任何提示都会非常有帮助

4

2 回答 2

2

假设点是P,线段是AB

A从片段中减去B并将P片段翻译为原点。OB'围绕原点旋转以带上x轴,给出OB". P'P"

现在,如果介于和P''x之间,则距离为。否则,如果,则距离为,如果,则距离为。0B''x|P''y|P''x<0√P''x²+P''y²P''x>B''x√(P''x-B''x)²+P''y²

在此处输入图像描述

于 2020-02-03T15:59:02.960 回答
0

这很容易解决......我只需要指定“线段”的域并测试域中投影点的包含情况。此解决方案适用于 2D 或 3D。

这是完成的代码:

        /// <summary>
        /// Finds the closest point on a vector given a test point
        /// </summary>
        /// <param name="testPoint"></param>
        /// <param name="startVertex"></param>
        /// <param name="segment"></param>
        /// <returns></returns>
        public  static Vec3 VectorClosestPoint(Vec3 testPoint, Vec3 startVertex,Vec3 segment)
        {


            Vec3 onCurve = new Vec3();

            Vec3 b = testPoint - startVertex;
            Vec3 proj = Project(b, segment, out double dotProduct);
            Vec3 onCurveTemp = startVertex + proj;
            Vec3 endVertex = startVertex + segment;

            // Specify the domain of the function. 
            // This part constraints the domain if the function is not infinite. 
            Domain domainX = new Domain(startVertex.X, endVertex.X);
            Domain domainY = new Domain(startVertex.Y, endVertex.Y);
            Domain domainZ = new Domain(startVertex.Z, endVertex.Z);


            // Constraints projected points to be in the line, given the specified
            // domain of the function
            bool onLine = OnLine(domainX, domainY, domainZ, onCurveTemp);

            if (dotProduct < 0) onCurve = startVertex;

            if (dotProduct > 0 && onLine == false) onCurve = endVertex;

            if (dotProduct > 0 && onLine == true) onCurve = onCurveTemp;


            return onCurve;


        }



        /// <summary>
        /// Returns the dot product of two vectors 
        /// This value equals vecA.Magnitude * vecB.Magnitude * cos(theta), where theta is the angle between both vectors.
        /// </summary>
        /// <param name="vecA"></param>
        /// <param name="VecB"></param>
        /// <returns></returns>
        public static double DotProduct(Vec3 vecA, Vec3 VecB)
        {
            return vecA.X * VecB.X + vecA.Y * VecB.Y + vecA.Z * VecB.Z;
        }



        /// <summary>
        /// Tests whether a Point lies on a vector
        /// </summary>
        /// <param name="domainX">X- Domain</param>
        /// <param name="domainY"> Y - Domain </param>
        /// <param name="domainZ">Z - Domain</param>
        /// <param name="pt">Point to test for inclusion </param>
        /// <returns>Returns true if point is on the line, false otherwise</returns>
        public static bool OnLine(Domain domainX, Domain domainY, Domain domainZ, Vec3 pt)

        {

            if (Domain.InDomain(domainX.Min, domainX.Max, pt.X) && Domain.InDomain(domainY.Min, domainY.Max, pt.Y) &&
              Domain.InDomain(domainZ.Min, domainZ.Max, pt.Z))
            {
                return true;
            }


            else return false;
        }


        /// <summary>
        /// Projection of vecA on to vecB
        /// </summary>
        /// <param name="vecA"></param>
        /// <param name="vecB"></param>
        /// <returns></returns>
        public static Vec3 Project(Vec3 vecA, Vec3 vecB, out double dotProduct)
        {
            dotProduct = DotProduct(vecA, vecB);
            return dotProduct / vecB.SqrMagnitude * vecB;
            // or to save Sqr operation return dotProduct / DotProduct(vecB, vecB) * vecB;
        }





/// <summary>
/// Tests whether a number is inside a domain
/// </summary>
/// <param name="minVal">Minimum value</param>
/// <param name="maxVal">Maximum value</param>
/// <param name="numToTest">Number to test </param>
/// <returns>True if in domain, false otherwise </returns>
public static bool InDomain(double minVal, double maxVal, double numToTest)
{
    double min = 0;
    double max = 0;
    if (minVal > maxVal)
    {
        min = maxVal;
        max = minVal;
    }

    if (minVal < maxVal)
    {
        min = minVal;
        max = maxVal;
    }


    if (numToTest >= min && numToTest <= max) return true;

    else return false;

}   
于 2020-02-04T16:17:36.157 回答