点から直線までの最近点を得る

f:id:startrekker:20170611230026p:plain

これも内積(Dot Product)で求まる。


|AX|を内積で求めるのがポイント。


線分PAを引くと、直角三角形PAXができる。

cosA = |AX| / |AP|

cosA|AP| = |AX|

|AX| = |AP|cosA ・・・① となる。


また、内積の公式は AP・AB = |AP| * |AB| * cosA ・・・②である。


②を変形すると、

|AP| = (AP・AB) / (|AB| * cosA)


①、②より、|AX| = (AP・AB) / (|AB| * cosA) * cosA

ゆえに、|AX| = (AP・AB) / |AB|・・・③


点Xの位置はAB上にあるので、

点X = A + (|AX| / |AB|) * ベクトルAB

点X = A + ( AP・AB / |AB|) / |AB| * ベクトルAB


したがって、

点X = (0,0,0) + (0*2 + 3*6 + 0*0 / / √40) / √40 * ベクトルAB

= (0,0,0) + (18/√40) / √40 * ベクトルAB

= (0,0,0) + 2.848/6.324 * ベクトルAB

= (0,0,0) + 0.450 * 2 + 0.450 * 6 + 0.450 * 0

≒ (0.9, 2.7, 0.0)


以下、C#ソースコード

using System;
using System.Windows.Media.Media3D;

namespace Calc
{
    public static class Logic
    {
        /// <summary>
        /// 点Pから直線ABまでの最近点Xを得る
        /// </summary>
        /// <param name="p">点P</param>
        /// <param name="a">点A(直線ABの1点目)</param>
        /// <param name="b">点B(直線ABの2点目)</param>
        /// <returns>最近点X</returns>
        static public Point3D GetNearestPoint(Point3D p, Point3D a, Point3D b)
        {
            Vector3D vAP = new Vector3D(p.X - a.X, p.Y - a.Y, p.Z - a.Z);
            Vector3D vAB = new Vector3D(b.X - a.X, b.Y - a.Y, b.Z - a.Z);

            double AXLength = Vector3D.DotProduct(vAP, vAB) / vAB.Length;

            Point3D X = a + (AXLength / vAB.Length) * vAB;
            return X;
        }
    }
}