E8本(数学)    次のE8本(数学)の問題へ    前のE8本(数学)の問題へ

E8本(数学) 033 Distance


問題へのリンク


C#のソース

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static string InputPattern = "InputX";

    static List<string> GetInputList()
    {
        var WillReturn = new List<string>();

        if (InputPattern == "Input1") {
            WillReturn.Add("0 5");
            WillReturn.Add("1 1");
            WillReturn.Add("3 0");
            //4.123105625618
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("-40 -30");
            WillReturn.Add("-50 -10");
            WillReturn.Add("-20 -20");
            //15.811388300842
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("1000000000 1000000000");
            WillReturn.Add("-1000000000 -1000000000");
            WillReturn.Add("0 -1000000000");
            //2236067977.499789714813
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    struct PointDef
    {
        internal decimal X;
        internal decimal Y;
    }

    struct SegmentDef
    {
        internal PointDef StaPos;
        internal PointDef EndPos;
    }

    static void Main()
    {
        List<string> InputList = GetInputList();

        decimal[] wkArr = { };
        Action<string> SplitAct = pStr =>
            wkArr = pStr.Split(' ').Select(pX => decimal.Parse(pX)).ToArray();

        PointDef PointA, PointB, PointC;
        SplitAct(InputList[0]); PointA.X = wkArr[0]; PointA.Y = wkArr[1];
        SplitAct(InputList[1]); PointB.X = wkArr[0]; PointB.Y = wkArr[1];
        SplitAct(InputList[2]); PointC.X = wkArr[0]; PointC.Y = wkArr[1];

        SegmentDef SegmentBC;
        SegmentBC.StaPos = PointB; SegmentBC.EndPos = PointC;

        decimal DistanceSP = GetDistanceSP(SegmentBC, PointA);
        Console.WriteLine(DistanceSP);
    }

    // 点と線分の距離を求める
    static decimal GetDistanceSP(SegmentDef pSegment, PointDef pPoint)
    {
        // 判定1 p1を始点とし、pまでのベクトルとp2までのベクトルの内積で判定
        PointDef Vector_p1_p = SetVector(pSegment.StaPos, pPoint);
        PointDef Vector_p1_p2 = SetVector(pSegment.StaPos, pSegment.EndPos);
        if (DeriveDot(Vector_p1_p, Vector_p1_p2) < 0M) {
            return DeriveABS(Vector_p1_p);
        }

        // 判定2 p2を始点とし、pまでのベクトルとp1までのベクトルの内積で判定
        PointDef Vector_p2_p = SetVector(pSegment.EndPos, pPoint);
        PointDef Vector_p2_p1 = SetVector(pSegment.EndPos, pSegment.StaPos);
        if (DeriveDot(Vector_p2_p, Vector_p2_p1) < 0M) {
            return DeriveABS(Vector_p2_p);
        }

        return GetDistanceLP(pSegment, pPoint);
    }

    // 始点と終点の座標を引数として、始点から終点へのベクトルを返す
    static PointDef SetVector(PointDef pStaPoint, PointDef pEndPoint)
    {
        PointDef WillReturn;
        WillReturn.X = pEndPoint.X - pStaPoint.X;
        WillReturn.Y = pEndPoint.Y - pStaPoint.Y;
        return WillReturn;
    }

    // 内積を求める
    static decimal DeriveDot(PointDef pVector1, PointDef pVector2)
    {
        return pVector1.X * pVector2.X + pVector1.Y * pVector2.Y;
    }

    // 外積を求める
    static decimal DeriveCross(PointDef pVector1, PointDef pVector2)
    {
        return pVector1.X * pVector2.Y - pVector1.Y * pVector2.X;
    }

    // ベクトルの大きさを求める
    static decimal DeriveABS(PointDef pVector)
    {
        decimal wkNorm = DeriveNorm(pVector);
        double wkSqrt = Math.Sqrt((double)wkNorm);
        return (decimal)wkSqrt;
    }

    // ベクトルのNormを求める
    static decimal DeriveNorm(PointDef pVector)
    {
        return pVector.X * pVector.X + pVector.Y * pVector.Y;
    }

    // 点と直線の距離を求める
    static decimal GetDistanceLP(SegmentDef pSegment, PointDef pPoint)
    {
        PointDef Vector_p1_p2 = SetVector(pSegment.StaPos, pSegment.EndPos);
        PointDef Vector_p1_p = SetVector(pSegment.StaPos, pPoint);

        // 平行四辺形の面積 (外積の絶対値) を求める
        decimal wkCross = DeriveCross(Vector_p1_p2, Vector_p1_p);
        decimal wkABS = DeriveABS(Vector_p1_p2);

        return Math.Abs(wkCross) / wkABS;
    }
}


解説

点と線分の距離を求める
メソッドを用意してます。