using System;
using System.Collections.Generic;
using System.Linq;
// Q061 距離 https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_D&lang=jp
class Program
{
static string InputPattern = "InputX";
static List<string> GetInputList()
{
var WillReturn = new List<string>();
if (InputPattern == "Input1") {
WillReturn.Add("3");
WillReturn.Add("0 0 1 0 0 1 1 1");
WillReturn.Add("0 0 1 0 2 1 1 2");
WillReturn.Add("-1 0 1 0 0 1 0 -1");
//1.0000000000
//1.4142135624
//0.0000000000
}
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();
foreach (string EachStr in InputList.Skip(1)) {
SplitAct(EachStr);
PointDef Point1, Point2, Point3, Point4;
Point1.X = wkArr[0]; Point1.Y = wkArr[1];
Point2.X = wkArr[2]; Point2.Y = wkArr[3];
Point3.X = wkArr[4]; Point3.Y = wkArr[5];
Point4.X = wkArr[6]; Point4.Y = wkArr[7];
SegmentDef Segment1;
Segment1.StaPos = Point1; Segment1.EndPos = Point2;
SegmentDef Segment2;
Segment2.StaPos = Point3; Segment2.EndPos = Point4;
Console.WriteLine(GetDistance(Segment1, Segment2));
}
}
// 線分と線分の距離を求める
static decimal GetDistance(SegmentDef pSegment1, SegmentDef pSegment2)
{
// 線分同士が交差する場合
if (IsIntersect(pSegment1, pSegment2)) {
return 0M;
}
var KouhoList = new List<decimal>();
KouhoList.Add(GetDistanceSP(pSegment1, pSegment2.StaPos));
KouhoList.Add(GetDistanceSP(pSegment1, pSegment2.EndPos));
KouhoList.Add(GetDistanceSP(pSegment2, pSegment1.StaPos));
KouhoList.Add(GetDistanceSP(pSegment2, pSegment1.EndPos));
return KouhoList.Min();
}
// 線分同士の交差判定
static bool IsIntersect(SegmentDef pSegment1, SegmentDef pSegment2)
{
PointDef P1 = pSegment1.StaPos;
PointDef P2 = pSegment1.EndPos;
PointDef P3 = pSegment2.StaPos;
PointDef P4 = pSegment2.EndPos;
if (CCW(P1, P2, P3) * CCW(P1, P2, P4) <= 0 &&
CCW(P3, P4, P1) * CCW(P3, P4, P2) <= 0) {
return true;
}
return false;
}
static int CCW(PointDef pPointA, PointDef pPointB, PointDef pPointC)
{
const int COUNTER_CLOCKWISE = 1;
const int CLOCKWISE = -1;
const int ONLINE_BACK = 2;
const int ONLINE_FRONT = -2;
const int ON_SEGMENT = 0;
PointDef VectorA = SetVector(pPointA, pPointB);
PointDef VectorB = SetVector(pPointA, pPointC);
// 外積 A*Bを求める
decimal Cross = DeriveCross(VectorA, VectorB);
// Aの半時計回りの方向にBが存在する
if (Cross > 0) {
return COUNTER_CLOCKWISE;
}
// Aの時計回りの方向にBが存在する
if (Cross < 0) {
return CLOCKWISE;
}
// 3点が1直線にある場合
// 内積がマイナスなら、ベクトルの向きは反対
decimal Dot = DeriveDot(VectorA, VectorB);
if (Dot < 0) {
return ONLINE_BACK;
}
decimal NormA = DeriveNorm(VectorA);
decimal NormB = DeriveNorm(VectorB);
if (NormA < NormB) {
return ONLINE_FRONT;
}
return ON_SEGMENT;
}
// 点と線分の距離を求める
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;
}
}