Language: C++

#include <bits/stdc++.h>
using namespace std;

namespace geometry {
	// ???????????§??????
	
	typedef complex<double> Point;
	
	struct Segment {
		Point p1, p2;
		Segment(const Point &p1 = Point(), const Point &p2 = Point()): p1(p1), p2(p2){}
	};
	
	struct Circle {
		Point p;
		double r;
		Circle(const Point &p = Point(), double r = 0.0): p(p), r(r){}
	};
	
	typedef Point Vector;
	typedef Segment Line;
	typedef vector<Point> Polygon;
	
	
	// ??\??????
	
	inline istream & operator >> (istream &is, Point &p){
		double x, y;
		is >> x >> y;
		p.real(x), p.imag(y);
		return is;
	}
	
	inline istream & operator >> (istream &is, Segment &s){
		return is >> s.p1 >> s.p2;
	}
	
	inline istream & operator >> (istream &is, Circle &c){
		return is >> c.p >> c.r;
	}
	
	inline ostream & operator << (ostream &os, Segment &s){
		return os << "{" << s.p1 << ", " << s.p2 << "}";
	}
	
	inline ostream & operator << (ostream &os, Circle &c){
		return os << "{" << c.p << ", " << c.r << "}";
	}
	
	inline ostream & operator << (ostream &os, Polygon &g){
		os << "{";
		for (int i = 0; i < g.size(); i++){
			if (i) os << ", ";
			os << g[i];
		}
		return os << "}";
	}
	
	
	// ?????°, ??????
	
	const double PI = acos(-1);
	const double EPS = 1e-2;
	const double INF = 1e16;
	const int COUNTER_CLOCKWISE = 1;
	const int CLOCKWISE 		= -1;
	const int ONLINE_BACK		= 2;
	const int ONLINE_FRONT		= -2;
	const int ON_SEGMENT		= 0;
	const int OUT				= 0;
	const int ON				= 1;
	const int IN				= 2;
	
	inline double square(double a){return a * a;}
	inline bool equal(double a, double b){return abs(a - b) < EPS;}
	inline bool equalVector(const Vector &a, const Vector &b){return equal(a.real(), b.real()) && equal(a.imag(), b.imag());}
	inline double norm(const Point &a){return square(a.real()) + square(a.imag());}
	inline double dot(const Point &a, const Point &b){return (conj(a) * b).real();}
	inline double cross(const Point &a, const Point &b){return (conj(a) * b).imag();}
	inline double toDeg(double t){return t / PI * 180;}
	inline double toRad(double t){return t / 180 * PI;}
	
	#define curr(v, i) v[i]
	#define next(v, i) v[(i + 1) % v.size()]
	#define prev(v, i) v[(i - 1 + v.size()) % v.size()]
	
	
	// ????????¢??° (x ??§?¨?, y ??§?¨?, ????§?)
	// ????§?????????????????????? Point rp ?????£??\????????????
	
	bool cmpx(const Point &a, const Point &b){
		if (!equal(a.real(), b.real())) return a.real() < b.real();
		return b.imag() < b.imag();
	}
	
	bool cmpy(const Point &a, const Point &b){
		if (!equal(a.imag(), b.imag())) return a.imag() < b.imag();
		return a.real() < b.real();
	}
	
	Point rp;
	bool cmparg(const Point &a, const Point &b){
		double rada = arg(a - rp); if (rada < 0.0) rada += 2 * PI;
		double radb = arg(b - rp); if (radb < 0.0) radb += 2 * PI;
		if (!equal(rada, radb)) return rada < radb;
		return norm(a) < norm(b);
	}
	
	
	// ??´???, ??????
	
	bool orthgonal(const Vector &a, const Vector &b){
		return equal(dot(a, b), 0.0);
	}
	
	bool parallel(const Vector &a, const Vector &b){
		return equal(cross(a, b), 0.0);
	}
	
	
	// ????°?, ?°???±
	
	Point project(const Segment &s, const Point &p){
		Vector base = s.p2 - s.p1;
		double r = dot(p - s.p1, base) / norm(base);
		return s.p1 + base * r;
	}
	
	Point reflect(const Segment &s, const Point &p){
		return p + (project(s, p) - p) * 2.0;
	}
	
	
	// ??????????????????
	
	int ccw(const Point &p0, const Point &p1, const Point &p2){
		Vector a = p1 - p0;
		Vector b = p2 - p0;
		if (cross(a, b) > EPS) return COUNTER_CLOCKWISE;
		if (cross(a, b) < -EPS) return CLOCKWISE;
		if (dot(a, b) < -EPS) return ONLINE_BACK;
		if (norm(a) > norm(b)) return ONLINE_FRONT;
		return ON_SEGMENT;
	}
	
	
	// ?????¢
	
	double distanceLP(const Line &l, const Point &p){
		return abs(cross(l.p2 - l.p1, p - l.p1) / abs(l.p2 - l.p1));
	}
	
	double distanceSP(const Segment &s, const Point &p){
		if (dot(s.p2 - s.p1, p - s.p1) < 0.0) return abs(p - s.p1);
		if (dot(s.p1 - s.p2, p - s.p2) < 0.0) return abs(p - s.p2);
		return distanceLP(s, p);
	}
	
	bool intersect(const Segment &s1, const Segment &s2);
	double distance(const Segment &s1, const Segment &s2){
		if (intersect(s1, s2)) return 0.0;
		return min(
			min(distanceSP(s1, s2.p1), distance(s1, s2.p2)),
			min(distanceSP(s2, s1.p1), distance(s2, s1.p2))
		);
	}
	
	
	// ????????????
	
	bool intersect(const Segment &s1, const Segment &s2){
		return ccw(s1.p1, s1.p2, s2.p1) * ccw(s1.p1, s1.p2, s2.p2) <= 0 &&
			ccw(s2.p1, s2.p2, s1.p1) * ccw(s2.p1, s2.p2, s1.p2) <= 0;
	}
	
	int intersect(const Circle &c, const Segment &s){
		// ???????????° (0 ~ 2) ?????????
		double dist = distanceSP(s, c.p) - c.r;
		if (equal(dist, 0.0)) return 1;
		if (dist < 0.0) return 2;
		return 0;
	}
	
	int intersect(const Circle &c1, const Circle &c2){
		// ???????????° (0 ~ 2) ?????????
		double dist = abs(c1.p - c2.p) - (c1.r + c2.r);
		if (equal(dist, 0.0)) return 1;
		if (dist < 0.0) return 2;
		return 0;
	}
	
	
	// ??????
	
	Point crossPoint(const Segment &s1, const Segment &s2){
		Vector base = s2.p2 - s2.p1;
		double d1 = abs(cross(base, s1.p1 - s2.p1));
		double d2 = abs(cross(base, s1.p2 - s2.p1));
		
		// !! ????????´?????¶????????????????????\????????¨ 0 ?????? !!
		assert(!equal(d1 + d2, 0.0));
		
		double t = d1 / (d1 + d2);
		return s1.p1 + (s1.p2 - s1.p1) * t;
	}
	
	vector<Point> crossPoints(const Circle &c, const Line &l){
		vector<Point> res;
		if (!intersect(c, l)) return res;
		
		Vector pr = project(l, c.p);
		Vector e = (l.p2 - l.p1) / abs(l.p2 - l.p1);
		double base = sqrt(c.r * c.r - norm(pr - c.p));
		res.push_back(pr + e * base);
		res.push_back(pr - e * base);
		if (equalVector(res[0], res[1])) res.pop_back();
		return res;
	}
	
	vector<Point> crossPoints(const Circle &c1, const Circle &c2){
		vector<Point> res;
		if (!intersect(c1, c2)) return res;
		
		double d = abs(c1.p - c2.p);
		double a = acos(square(c1.r) + square(d) - square(c2.r) / (2 * c2.r * d));
		double t = arg(c2.p - c1.p);
		res.push_back(c1.p + polar(c1.r, t + a));
		res.push_back(c1.p + polar(c1.r, t - a));
		if (equalVector(res[0], res[1])) res.pop_back();
	}
	
	
	// ??????
	
	int contains(const Polygon &g, const Point &p){
		int n = g.size();
		bool res = false;
		for (int i = 0; i < n; i++){
			Point a = g[i] - p;
			Point b = g[(i + 1) % n] - p;
			if (abs(cross(a, b)) < EPS && dot(a, b) < EPS) return ON;
			if (a.imag() > b.imag()) swap(a, b);
			if (a.imag() < EPS && EPS < b.imag() && cross(a, b) > EPS) res = !res;
		}
		return res ? IN : OUT;
	}
	
	
	// ??????
	
	Polygon convexHull(vector<Point> s){
		Polygon u, l;
		if (s.size() < 3) return s;
		sort(s.begin(), s.end());
		u.push_back(s[0]);
		u.push_back(s[1]);
		l.push_back(s[s.size() - 1]);
		l.push_back(s[s.size() - 2]);
		
		for (int i = 2; i < s.size(); i++){
			int n = u.size();
			while (n >= 2 && ccw(u[n - 2], u[n - 1], s[i]) != CLOCKWISE){
				u.pop_back();
				n--;
			}
			u.push_back(s[i]);
		}
		
		for (int i = s.size() - 3; i >= 0; i--){
			int n = l.size();
			while (n >= 2 && ccw(l[n - 2], l[n - 1], s[i]) != CLOCKWISE){
				l.pop_back();
				n--;
			}
			l.push_back(s[i]);
		}
		
		reverse(l.begin(), l.end());
		for (int i = u.size() - 2; i >= 1; i--){
			l.push_back(u[i]);
		}
		
		return l;
	}
	
	
	// ???????§???¢??????
	
	Polygon convexCut(const Polygon &g, const Line &l){
		Polygon res;
		for (int i = 0; i < g.size(); i++){
			const Point &a = curr(g, i);
			const Point &b = next(g, i);
			if (ccw(l.p1, l.p2, a) != CLOCKWISE){
				res.push_back(a);
			}
			if (ccw(l.p1, l.p2, a) * ccw(l.p1, l.p2, b) < 0){
				res.push_back(crossPoint(Line(a, b), l));
			}
		}
		
		return res;
	}
}

namespace std {
	bool operator < (const geometry::Point &a, const geometry::Point &b){
		return geometry::cmpx(a, b);
	}
}


using namespace geometry;

bool intersect(const Polygon &g, const Polygon &h)
{
	for (int i = 0; i < g.size(); i++){
		for (int j = 0; j < h.size(); j++){
			Segment u(curr(g, i), next(g, i));
			Segment v(curr(h, j), next(h, j));
			if (intersect(u, v)) return true;
		}
	}
	
	for (int i = 0; i < g.size(); i++){
		if (contain(h, g[i])) return true;
	}
	for (int i = 0; i < h.size(); i++){
		if (contain(g, h[i])) return true;
	}
	
	return false;
}


int n;
double d;
Polygon tri[100];
Polygon sqr[100];
vector<int> graph[100];
vector<int> rgraph[100];

void dfs(int v, vector<int> &vs, vector<bool> &used)
{
	used[v] = true;
	for (int to : graph[v]){
		if (!used[to]) dfs(to, vs, used);
	}
	vs.push_back(v);
}

void rdfs(int v, int k, vector<bool> &used, vector<int> &cmp)
{
	used[v] = true;
	cmp[v] = k;
	for (int to : rgraph[v]){
		if (!used[to]) rdfs(to, k, used, cmp);
	}
}

vector<vector<int>> scc()
{
	vector<int> vs;
	vector<bool> used(n, false);
	vector<int> cmp(n);
	
	for (int i = 0; i < n; i++){
		if (!used[i]) dfs(i, vs, used);
	}
	
	used.assign(n, false);
	
	int k = 0;
	for (int i = vs.size() - 1; i >= 0; i--){
		if (!used[vs[i]]) rdfs(vs[i], k++, used, cmp);
	}
	
	vector<vector<int>> res(k);
	
	for (int i = 0; i < n; i++){
		for (int to : graph[i]){
			if (cmp[i] == cmp[to]) continue;
			res[cmp[i]].push_back(cmp[to]);
		}
	}
	
	return res;
}

int solve()
{
	for (int i = 0; i < n; i++){
		for (int j = 0; j < 3; j++){
			Point &a = curr(tri[i], j);
			Point &b = prev(tri[i], j);
			Point &c = next(tri[i], j);
			if (equal(abs(b - a), abs(c - a))){
				swap(a, tri[i][2]);
				break;
			}
		}
		
		//cout << abs(tri[i][2] - tri[i][0]) << " " << abs(tri[i][2] - tri[i][1]) << endl;
		assert(equal(abs(tri[i][2] - tri[i][0]), abs(tri[i][2] - tri[i][1])));
	}
	
	for (int i = 0; i < n; i++){
		sqr[i].resize(4);
		
		vector<Vector> V = {{0, 1}, {0, -1}};
		bool f = false;
		for (auto &v : V){
			Vector a = tri[i][1] - tri[i][0];
			Vector nv = a / abs(a) * v * d;
			
			if (dot(tri[i][2] - tri[i][0], nv) < 0.0) continue;
			
			sqr[i][0] = tri[i][0];
			sqr[i][1] = tri[i][1];
			sqr[i][2] = tri[i][1] + nv;
			sqr[i][3] = tri[i][0] + nv;
			f = true;
		}
		assert(f);
	}
	
	for (int i = 0; i < n; i++){
		graph[i].clear();
		rgraph[i].clear();
	}
	
	for (int i = 0; i < n; i++){
		for (int j = 0; j < n; j++){
			if (i == j) continue;
			if (intersect(sqr[i], tri[j])){
				graph[i].push_back(j);
				rgraph[j].push_back(i);
			}
		}
	}
	
	vector<vector<int>> sccgraph = scc();
	
	vector<int> indeg(sccgraph.size(), 0);
	for (int i = 0; i < sccgraph.size(); i++){
		for (int to : sccgraph[i]){
			if (i == to) continue;
			indeg[to]++;
		}
	}
	
	int res = 0;
	for (int i = 0; i < sccgraph.size(); i++){
		if (indeg[i] == 0) res++;
	}
	
	return res;
}

int main()
{
	while (cin >> n >> d, n){
		for (int i = 0; i < n; i++){
			tri[i].resize(3);
			for (int j = 0; j < 3; j++){
				cin >> tri[i][j];
			}
		}
		
		cout << solve() << endl;
	}
	
	return 0;
}

Compiler output:
a.cc: In function 'bool intersect(const geometry::Polygon&, const geometry::Polygon&)':
a.cc:326:21: error: 'contain' was not declared in this scope
  326 |                 if (contain(h, g[i])) return true;
      |                     ^~~~~~~
a.cc:329:21: error: 'contain' was not declared in this scope
  329 |                 if (contain(g, h[i])) return true;
      |                     ^~~~~~~
a.cc: In function 'std::vector<std::complex<double> > geometry::crossPoints(const Circle&, const Circle&)':
a.cc:230:9: warning: control reaches end of non-void function [-Wreturn-type]
  230 |         }
      |         ^