#include<iostream>
#include<vector>
#include<queue>
#include<functional>
#include<cfloat>
#include<tuple>
#include<set>
#include<stack>
#include<algorithm>

const double INF = DBL_MAX / 3.0;

const double EPS = 1e-10;
enum POSITION {ONLINE_FRONT = -2, CLOCKWISE, ON_SEGMENT, COUNTER_CLOCKWISE, ONLINE_BACK};
// class
class Point;
class Segment;
class Line;
class Polygon;
// member
class Point {
double x_value, y_value;
public:
Point() :x_value(0.0), y_value(0.0) {}
Point(double d) :x_value(d), y_value(d) {}
Point(double a, double b) :x_value(a), y_value(b) {}
double x() const {return x_value;}
double y() const {return y_value;}
double x(double d) {return x_value = d;}
double y(double d) {return y_value = d;}
const Point operator-() const;
const Point& operator=(const Point&);
const Point& operator+=(const Point&);
const Point& operator-=(const Point&);
const Point& operator*=(const Point&);
const Point& operator/=(const Point&);
double dot(const Point&) const;
double cross(const Point&) const;
double abs() const;
double norm() const;
const Point normalize() const;
double distance(const Point&) const;
double distance(const Segment&) const;
double distance(const Line&) const;
bool intersect(const Point&) const;
bool intersect(const Segment&) const;
bool intersect(const Line&) const;
const Point projection(const Line&) const;
const Point reflection(const Line&) const;
POSITION ccw(const Point&, const Point&) const;
};
bool operator==(const Point& lhs, const Point& rhs);
bool operator!=(const Point& lhs, const Point& rhs);
bool operator<(const Point& lhs, const Point& rhs);
bool operator>(const Point& lhs, const Point& rhs);
bool operator<=(const Point& lhs, const Point& rhs);
bool operator>=(const Point& lhs, const Point& rhs);
const Point operator+(const Point& lhs, const Point& rhs);
const Point operator-(const Point& lhs, const Point& rhs);
const Point operator*(const Point& lhs, const Point& rhs);
const Point operator/(const Point& lhs, const Point& rhs);
class Segment {
Point source_point, target_point;
public:
Segment(double x1 = 0.0, double y1 = 0.0, double x2 = 0.0, double y2 = 0.0) :source_point(Point(x1, y1)), target_point(Point(x2, y2)) {}
Segment(const Point& a, const Point& b) :source_point(a), target_point(b) {}
const Point& source() const {return source_point;}
const Point& target() const {return target_point;}
const Point& source(const Point& p) {return source_point = p;}
const Point& target(const Point& p) {return target_point = p;}
const Line line() const;
double distance(const Point&) const;
double distance(const Segment&) const;
double distance(const Line&) const;
bool intersect(const Point&) const;
bool intersect(const Segment&) const;
bool intersect(const Line&) const;
POSITION ccw(const Point&) const;
};
class Line {
Point source_point, target_point;
public:
Line(double x1 = 0.0, double y1 = 0.0, double x2 = 0.0, double y2 = 0.0) :source_point(Point(x1, y1)), target_point(Point(x2, y2)) {}
Line(const Point& a, const Point& b) :source_point(a), target_point(b) {}
const Point& source() const {return source_point;}
const Point& target() const {return target_point;}
const Point& source(const Point& p) {return source_point = p;}
const Point& target(const Point& p) {return target_point = p;}
const Segment segment() const;
double distance(const Point&) const;
double distance(const Segment&) const;
double distance(const Line&) const;
bool intersect(const Point&) const;
bool intersect(const Segment&) const;
bool intersect(const Line&) const;
const Point projection(const Point&) const;
const Point reflection(const Point&) const;
const Point crosspoint(const Line&) const;
POSITION ccw(const Point&) const;
};
class Polygon {
std::vector<Point> point;
public:
Polygon() {}
explicit Polygon(std::vector<Point> p) :point(p) {}
const std::vector<Point>& vertex() const {return point;}
const Point& vertex(int i) const {return point.at(i);}
const std::vector<Segment> edge() const {
std::vector<Segment> result;
for(int i = 0; i < size(); ++i) result.push_back(Segment(vertex(i), vertex((i + 1) % size())));
return result;
}
const Segment edge(int i) const {return Segment(vertex(i), vertex((i + 1) % size()));}
int size() const {return point.size();}
void add(const Point&);
double area() const;
bool convex() const;
bool include(const Point&) const;
bool intersect(const Polygon&) const;
bool on_edge(const Point&) const;
const Polygon convex_hull() const;
};
// Point
bool operator==(const Point& lhs, const Point& rhs) {return lhs.x() == rhs.x() && lhs.y() == rhs.y();}
bool operator!=(const Point& lhs, const Point& rhs) {return lhs.x() != rhs.x() || lhs.y() != rhs.y();}
bool operator<(const Point& lhs, const Point& rhs) {return lhs.x() != rhs.x() ? lhs.x() < rhs.x() : lhs.y() < rhs.y();}
bool operator>(const Point& lhs, const Point& rhs) {return lhs.x() != rhs.x() ? lhs.x() > rhs.x() : lhs.y() > rhs.y();}
bool operator<=(const Point& lhs, const Point& rhs) {return lhs.x() != rhs.x() ? lhs.x() < rhs.x() : lhs.y() <= rhs.y();}
bool operator>=(const Point& lhs, const Point& rhs) {return lhs.x() != rhs.x() ? lhs.x() > rhs.x() : lhs.y() >= rhs.y();}
const Point operator+(const Point& lhs, const Point& rhs) {return Point(lhs.x() + rhs.x(), lhs.y() + rhs.y());}
const Point operator-(const Point& lhs, const Point& rhs) {return Point(lhs.x() - rhs.x(), lhs.y() - rhs.y());}
const Point operator*(const Point& lhs, const Point& rhs) {return Point(lhs.x() * rhs.x(), lhs.y() * rhs.y());}
const Point operator/(const Point& lhs, const Point& rhs) {return Point(lhs.x() / rhs.x(), lhs.y() / rhs.y());}
const Point Point::operator-() const {return Point(-x(), -y());}
const Point& Point::operator=(const Point& p) {x(p.x()); y(p.y()); return *this;}
const Point& Point::operator+=(const Point& p) {return *this = *this + p;}
const Point& Point::operator-=(const Point& p) {return *this = *this - p;}
const Point& Point::operator*=(const Point& p) {return *this = *this * p;}
const Point& Point::operator/=(const Point& p) {return *this = *this / p;}
double Point::dot(const Point& p) const {return x() * p.x() + y() * p.y();}
double Point::cross(const Point& p) const {return x() * p.y() - y() * p.x();}
double Point::abs() const {return hypot(x(), y());}
double Point::norm() const {return x() * x() + y() * y();}
const Point Point::normalize() const {return abs() == 0.0 ? Point(0.0, 0.0) : Point(x(), y()) / abs();}
double Point::distance(const Point& p) const {return (p - (*this)).abs();}
double Point::distance(const Segment& s) const {return s.distance(*this);}
double Point::distance(const Line& l) const {return l.distance(*this);}
bool Point::intersect(const Point& p) const {return *this == p;}
bool Point::intersect(const Segment& s) const {return s.intersect(*this);}
bool Point::intersect(const Line& l) const {return l.intersect(*this);}
const Point Point::projection(const Line& l) const {return l.projection(*this);}
const Point Point::reflection(const Line& l) const {return l.reflection(*this);}
POSITION Point::ccw(const Point& b, const Point& p) const {
const Point& a = *this;
Point v1 = b - a;
Point v2 = p - a;
if(v1.cross(v2) > EPS) return COUNTER_CLOCKWISE;
if(v1.cross(v2) < -EPS) return CLOCKWISE;
if(v1.dot(v2) < -EPS) return ONLINE_BACK;
if(v2.norm() - v1.norm() > EPS) return ONLINE_FRONT;
return ON_SEGMENT;
}
// Segment
const Line Segment::line() const {return Line(source(), target());}
double Segment::distance(const Point& p) const {
Point q = line().projection(p);
if(intersect(q)) return q.distance(p);
return std::min(source().distance(p), target().distance(p));
}
double Segment::distance(const Segment& s) const {
if(intersect(s)) return 0.0;
double a = distance(s.source());
double b = distance(s.target());
double c = s.distance(source());
double d = s.distance(target());
return std::min({a, b, c, d});
}
double Segment::distance(const Line& l) const {return l.distance(*this);}
bool Segment::intersect(const Point& p) const {return source().distance(p) + target().distance(p) - target().distance(source()) <= EPS;}
bool Segment::intersect(const Segment& s) const {
bool a = ccw(s.source()) * ccw(s.target()) <= 0;
bool b = s.ccw(source()) * s.ccw(target()) <= 0;
return a && b;
}
bool Segment::intersect(const Line& l) const {return l.intersect(*this);}
POSITION Segment::ccw(const Point& p) const {return source().ccw(target(), p);}
// Line
const Segment Line::segment() const {return Segment(source(), target());}
double Line::distance(const Point& p) const {return p.distance(projection(p));}
double Line::distance(const Segment& s) const {
if(intersect(s)) return 0.0;
double a = distance(s.source());
double b = distance(s.target());
return a < b ? a : b;
}
double Line::distance(const Line& l) const {return intersect(l) ? 0.0 : distance(l.source());}
bool Line::intersect(const Point& p) const {
Point v1 = source() - p;
Point v2 = target() - p;
return fabs(v2.cross(v1)) < EPS;
}
bool Line::intersect(const Segment& s) const {
Point v1 = target() - source();
Point v2 = s.source() - source();
Point v3 = s.target() - source();
return v1.cross(v2) * v1.cross(v3) <= EPS;
}
bool Line::intersect(const Line& l) const {
Point v1 = target() - source();
Point v2 = l.target() - l.source();
Point v3 = l.source() - source();
return fabs(v1.cross(v2)) > EPS || fabs(v1.cross(v3)) < EPS;
}
const Point Line::projection(const Point& p) const {
Point v1 = p - source();
Point v2 = source() - target();
return Point(source() + v2 * (v1.dot(v2) / v2.norm()));
}
const Point Line::reflection(const Point& p) const {
return p + (projection(p) - p) * 2.0;
}
const Point Line::crosspoint(const Line& l) const {
Point v1 = target() - source();
Point v2 = l.target() - l.source();
Point v3 = target() - l.source();
double a = v1.cross(v2);
double b = v1.cross(v3);
if(fabs(a) <= EPS && fabs(b) <= EPS) return l.source();
return l.source() + v2 * (b / a);
}
POSITION Line::ccw(const Point& p) const {return source().ccw(target(), p);}
// Polygon
void Polygon::add(const Point& p) {point.push_back(p);}
double Polygon::area() const {
double sum = 0.0;
for(int i = 0; i < size(); ++i) sum += vertex(i).cross(vertex((i+1) % size()));
return fabs(sum) / 2.0;
}
bool Polygon::convex() const {
POSITION direction = ONLINE_BACK;
for(int i = 1; i < size(); ++i) {
POSITION d = vertex(i - 1).ccw(vertex(i), vertex((i + 1) % size()));
if(d != CLOCKWISE && d != COUNTER_CLOCKWISE) continue;
if(direction == ONLINE_BACK) direction = d;
if(direction != d) return false;
}
return true;
}
bool Polygon::include(const Point& p) const {
bool in = false;
for(int i = 0; i < size(); ++i) {
Point a = vertex(i) - p;
Point b = vertex((i + 1) % size()) - p;
if(a.y() > b.y()) std::swap(a, b);
if(a.y() <= 0.0 && 0 < b.y() && a.cross(b) < 0.0) in = !in;
if(fabs(a.cross(b)) <= EPS && a.dot(b) <= EPS) return true;
}
return in;
}
bool Polygon::intersect(const Polygon& p) const {
for(const auto& e1: edge()) for(const auto& e2: p.edge()) if(e1.intersect(e2)) return true;
return false;
}
bool Polygon::on_edge(const Point& p) const {
for(int i = 0; i < size(); ++i) if(vertex(i).ccw(vertex((i + 1) % size()), p) == ON_SEGMENT) return true;
return false;
}
const Polygon Polygon::convex_hull() const {                // Andrew's Monotone Chain
Polygon result;
std::vector<Point> res;
std::vector<Point> original = vertex();
sort(original.begin(), original.end());
original.insert(original.end(), original.rbegin() + 1, original.rend());
for(const auto& v: original) {
while(res.size() >= 2 && res[res.size() - 2].ccw(res[res.size() - 1], v) == CLOCKWISE) res.pop_back();
res.push_back(v);
}
res.pop_back();
for(const auto& v: res) result.add(v);
return result;
}

// Edge
class Edge {
int from_value, to_value;
double weight_value;
public:
Edge() {}
Edge(int f, int t, double w) :from_value(f), to_value(t), weight_value(w) {}
int from() const {return from_value;}
int to() const {return to_value;}
double weight() const {return weight_value;}
};

// Graph
class Graph {
int size_value;
std::vector<std::vector<Edge>> edge_value;

public:
explicit Graph(int s) :size_value(s) {edge_value.resize(s);}

int size() const {return size_value;}
const std::vector<Edge>& edge(int v) const {return edge_value[v];}

void add(const Edge& e);
void add(int from, int to, double weight);
public:
std::vector<std::vector<int>> Kosaraju() const;
private:
void Kosaraju_dfs_postorder(int from, std::vector<bool>& visited, std::stack<int>& order) const;
std::vector<int> Kosaraju_dfs_decompose(const std::vector<std::vector<Edge>>& reverse_edge, int from, std::vector<bool>& visited) const;
};

// implements
void Graph::add(const Edge& e) {edge_value[e.from()].push_back(e);}
void Graph::add(int from, int to, double weight) {edge_value[from].push_back(Edge(from, to, weight));}
std::vector<std::vector<int>> Graph::Kosaraju() const {
std::vector<std::vector<int>> result;
std::vector<bool> visited(size(), false);
std::stack<int> order;
for(int v = 0; v < size(); ++v) if(!visited[v]) Kosaraju_dfs_postorder(v, visited, order);
std::vector<std::vector<Edge>> reverse_edge(size(), std::vector<Edge>());
for(int v = 0; v < size(); ++v) for(const auto& e: edge(v)) reverse_edge[e.to()].push_back(Edge(e.to(), e.from(), e.weight()));
visited = std::vector<bool>(size(), false);
while(!order.empty()) {
int v = order.top();
order.pop();
if(visited[v]) continue;
result.push_back(Kosaraju_dfs_decompose(reverse_edge, v, visited));
}
return result;
}
void Graph::Kosaraju_dfs_postorder(int from, std::vector<bool>& visited, std::stack<int>& order) const {
visited[from] = true;
for(const auto& e: edge(from)) if(!visited[e.to()]) Kosaraju_dfs_postorder(e.to(), visited, order);
order.push(from);
}
std::vector<int> Graph::Kosaraju_dfs_decompose(const std::vector<std::vector<Edge>>& reverse_edge, int from, std::vector<bool>& visited) const {
std::vector<int> result;
result.push_back(from);
visited[from] = true;
for(const auto& e: reverse_edge[from]) {
if(visited[e.to()]) continue;
std::vector<int> add = Kosaraju_dfs_decompose(reverse_edge, e.to(), visited);
result.insert(result.end(), add.begin(), add.end());
}
return result;
}

using namespace std; 
int main() {
int n, d;
while(cin >> n >> d, n | d) {
vector<Polygon> triangle(n);
for(auto &t: triangle) {
vector<Point> vertex(3);
for(auto &v: vertex) {
double x, y;
cin >> x >> y;
v = Point(x, y);
}
if(vertex[0].distance(vertex[1]) == vertex[0].distance(vertex[2])) swap(vertex[0], vertex[2]);
if(vertex[1].distance(vertex[0]) == vertex[1].distance(vertex[2])) swap(vertex[1], vertex[2]);
for(const auto &v: vertex) t.add(v);
}

vector<Polygon> light(n);
for(int i = 0; i < triangle.size(); ++i) {
Point n = (triangle[i].vertex(1) - triangle[i].vertex(0)).normalize();
if(triangle[i].vertex(0).ccw(triangle[i].vertex(1), triangle[i].vertex(2)) > 0) n = Point(-n.y(), n.x());
else                                                                            n = Point(n.y(), -n.x());
light[i].add(triangle[i].vertex(0));
light[i].add(triangle[i].vertex(0) + (n * d));
light[i].add(triangle[i].vertex(1) + (n * d));
light[i].add(triangle[i].vertex(1));
}

Graph g(n);
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j) {
if(i == j) continue;
bool shine = false;

// 辺の交差判定
for(const auto &l: light[i].edge())
for(const auto &t: triangle[j].edge())
if(l.intersect(t)) shine = true;
// 点の包含判定
for(const auto &v: light[i].vertex())
if(triangle[j].include(v)) shine = true;
for(const auto &v: triangle[j].vertex())
if(light[i].include(v)) shine = true;
// 線分と点の距離が0.01以下
for(const auto &l: light[i].edge())
for(const auto &t: triangle[j].edge())
if(l.distance(t) <= 0.01) shine = true;

if(!shine) continue;
g.add(Edge(i, j, 1));
}
}

auto scc = g.Kosaraju();
vector<int> indegree(scc.size(), 0);
for(int i = 0; i < scc.size(); ++i) {
for(int j = i + 1; j < scc.size(); ++j) {
for(const auto& v: scc[i]) for(const auto& e: g.edge(v)){
if(find(scc[j].begin(), scc[j].end(), e.to()) != scc[j].end()) ++indegree[j];
}
}
}
cout << count(indegree.begin(), indegree.end(), 0) << endl;
}
}

Measured memory_bytes: 1320