#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <map>
#include <set>
#include <algorithm>
#define MAXM 4000
using namespace std;
typedef struct POINT
{
int x;
int y;
int z;
POINT() {}
POINT(int x, int y, int z): x(x), y(y), z(z) {}
bool operator < (const POINT& p) const
{
if(x < p.x) return 1;
if((x == p.x) && (y < p.y)) return 1;
if((x == p.x) && (y == p.y) && (z < p.z)) return 1;
return 0;
}
}
POINT;
typedef struct EDGE
{
POINT p1;
POINT p2;
}
EDGE;
typedef struct NEWEDGE
{
int v1;
int v2;
}
NEWEDGE;
typedef struct SETITEM
{
double d;
int v;
SETITEM() {}
SETITEM(double d, int v): d(d), v(v) {}
bool operator < (const SETITEM& i) const
{
if(d < i.d) return 1;
if((d == i.d) && (v < i.v)) return 1;
return 0;
}
}
SETITEM;
typedef struct FOL
{
int v;
int i;
}
FOL;
EDGE Edge[MAXM];
NEWEDGE NewEdge[MAXM];
int Degree[MAXM];
int CurIndex[MAXM];
FOL Fol[MAXM * 2];
int iFol[MAXM];
POINT Point[MAXM];
double Dist[MAXM * 2];
double GetLength(double x1, double y1, double z1)
{
return sqrt((x1 * x1) + (y1 * y1) + (z1 * z1));
}
double GetLength(POINT& p1, POINT& p2)
{
return GetLength(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z);
}
double GetAngle(double x1, double y1, double z1, double x2, double y2, double z2)
{
return acos(
((x1 * x2) + (y1 * y2) + (z1 * z2))
/
(GetLength(x1, y1, z1) * GetLength(x2, y2, z2))
) * 180 / (atan(1) * 4);
}
/*void Enqueue(set<SETITEM>& Set, int w)
{
set<SETITEM>::iterator it = Set.find(w);
if((it != Set.end()) && (Dist[w] < it->d))
{
Set.erase(it);
}
Set.insert(SETITEM(Dist[w], w));
}*/
int GetIndex(int w)
{
if(w % 2)
{
return NewEdge[w / 2].v2;
}
else
{
return NewEdge[w / 2].v1;
}
}
int main()
{
int m, sss, ttt;
int x1, y1, z1, x2, y2, z2;
while(scanf("%d%d%d", &m, &sss, &ttt) > 0)
{
map<POINT, int> Map;
set<SETITEM> Set;
scanf("%d%d%d%d%d%d", &x1, &y1, &z1, &x2, &y2, &z2);
if((x1 == x2) && (y1 == y2) && (z1 == z2))
{
printf("0.0\n");
continue;
}
int n = 0;
for(int i = 0; i < m; i++)
{
scanf("%d%d%d%d%d%d",
&(Edge[i].p1.x),
&(Edge[i].p1.y),
&(Edge[i].p1.z),
&(Edge[i].p2.x),
&(Edge[i].p2.y),
&(Edge[i].p2.z));
if(Map.find(Edge[i].p1) == Map.end())
{
Map[Edge[i].p1] = n;
Point[n++] = Edge[i].p1;
//printf("1 %d\n", Map[Edge[i].p1]);
}
if(Map.find(Edge[i].p2) == Map.end())
{
Map[Edge[i].p2] = n;
Point[n++] = Edge[i].p2;
//printf("2 %d\n", Map[Edge[i].p2]);
}
}
for(int i = 0; i < m; i++)
{
NewEdge[i].v1 = Map[Edge[i].p1];
NewEdge[i].v2 = Map[Edge[i].p2];
//printf("%d->%d\n", NewEdge[0].v1, NewEdge[0].v2);
Degree[NewEdge[i].v1]++;
Degree[NewEdge[i].v2]++;
}
iFol[0] = 0;
for(int i = 0; i < n; i++)
{
iFol[i + 1] = iFol[i] + Degree[i];
}
for(int i = 0; i < n; i++)
{
CurIndex[i] = 0;
}
int e;
for(int i = 0; i < m; i++)
{
e = NewEdge[i].v1;
Fol[iFol[e] + CurIndex[e]++] = (FOL) {NewEdge[i].v2, (i * 2) + 1};
e = NewEdge[i].v2;
Fol[iFol[e] + CurIndex[e]++] = (FOL) {NewEdge[i].v1, i * 2};
}
for(int i = 0; i < m * 2; i++)
{
Dist[i] = 1e18;
}
int wStart = Map[POINT(x1, y1, z1)];
int wGoal = Map[POINT(x2, y2, z2)];
//printf("%d->%d\n", NewEdge[0].v1, NewEdge[0].v2);
for(int i = 0; i < m; i++)
{
if(NewEdge[i].v1 == wStart)
{
Dist[(i * 2) + 1] = GetLength(Edge[i].p1, Edge[i].p2);
int w = (i * 2) + 1;
Set.insert(SETITEM(Dist[w], w));
}
if(NewEdge[i].v2 == wStart)
{
Dist[(i * 2) + 0] = GetLength(Edge[i].p1, Edge[i].p2);
int w = (i * 2) + 0;
Set.insert(SETITEM(Dist[w], w));
}
}
while(!(Set.empty()))
{
SETITEM Item = *(Set.begin());
Set.erase(Set.begin());
int v = GetIndex(Item.v);
//printf("%d\n", Item.v);
if(v == wGoal)
{
printf("%lf\n", Dist[Item.v]);
break;
}
for(int i = iFol[v]; i < iFol[v + 1]; i++)
{
FOL t = Fol[i];
int r1, r2, r3 = t.i;
if(Item.v % 2)
{
r1 = GetIndex(Item.v / 2);
r2 = GetIndex((Item.v / 2) + 1);
}
else
{
r2 = GetIndex(Item.v / 2);
r1 = GetIndex((Item.v / 2) + 1);
}
double x1 = Point[r1].x - Point[r2].x;
double y1 = Point[r1].y - Point[r2].y;
double z1 = Point[r1].z - Point[r2].z;
double x2 = Point[r2].x - Point[r3].x;
double y2 = Point[r2].y - Point[r3].y;
double z2 = Point[r2].z - Point[r3].z;
double prev = Dist[Item.v];
double angle = GetAngle(x1, y1, z1, x2, y2, z2) / ttt;
double length = GetLength(Point[v], Point[GetIndex(t.i)]) / sss;
double newDist = prev + angle + length;
if(Dist[t.i] == 1e18)
{
Dist[t.i] = newDist;
Set.insert(SETITEM(Dist[t.i], t.i));
}
else if(newDist < Dist[t.i])
{
Set.erase(SETITEM(Dist[t.i], t.i));
Dist[t.i] = newDist;
Set.insert(SETITEM(Dist[t.i], t.i));
}
}
}
}
//printf("%lf\n", GetAngle(1, 0, 0, -3, 0, 0));
return 0;
}