#!/usr/bin/env python3
import sys
from collections import defaultdict
import random


def close(this, that, scale):
    dist = 25.4 * scale
    return (this[0] - that[0]) ** 2 + (this[1] - that[1]) ** 2 <= (2 * dist + this[2] / 2 + that[2] / 2) ** 2


def components(models):
    def close(this, that):
        return ((this[0] - that[0]) ** 2 + (this[1] - that[1]) ** 2) * 100 <= (2 * 254 + 5 * (this[2] + that[2])) ** 2

    GRANULARITY = 211
    models_for_bucket = defaultdict(list)
    for i, m in enumerate(models):
        x, y, diam = m
        models_for_bucket[x // GRANULARITY, y // GRANULARITY] += [i]
    edges = defaultdict(set)
    for x_, y_ in models_for_bucket:
        M = set()
        for dx in [-1, 0, 1]:
            for dy in [-1, 0, 1]:
                if (x_ + dx, y_ + dy) in models_for_bucket:
                    M.update(models_for_bucket[x_ + dx, y_ + dy])
        for a in models_for_bucket[x_, y_]:
            edges[a].update([b for b in M if a != b and close(models[a], models[b])])
    comp = dict()
    comps = 0
    for start in range(len(models)):
        if start in comp:
            continue
        comp[start] = comps
        Q = [start]
        while Q:
            R = []
            for u in Q:
                for v in edges[u]:
                    if v in comp:
                        continue
                    R.append(v)
                    comp[v] = comps
            Q = R
        comps += 1
    return comp


def main():
    with open(sys.argv[1], "r") as infile, sys.stdout as texfile:
        N = int(infile.readline())
        text = None
        if N > 5000:
            text = f"Too many models ({N})"

        models = []
        for _ in range(N):
            models.append(tuple(map(float, infile.readline().split())))

        comp = components(models)
        colours = {}
        for i in range(len(models)):
            if comp[i] == 0:
                colours[i] = "blue"
            if comp[i] == 1:
                colours[i] = "cyan"
            if comp[i] == 2:
                colours[i] = "brown"
            if comp[i] == 3:
                colours[i] = "green"
            if comp[i] == 4:
                colours[i] = "lime"
            if comp[i] == 5:
                colours[i] = "magenta"
            if comp[i] == 6:
                colours[i] = "olive"
            if comp[i] == 7:
                colours[i] = "orange"
            if comp[i] > 7:
                colours[i] = random.choice(["pink", "purple", "red", "teal", "violet", "yellow"])

        # Rescale to fit in 5x5 cm

        IMAGE_SIZE = 5  # in centimeters
        xs = set()
        ys = set()
        for i, model in enumerate(models):
            x, y, d = model
            xs.add(x - d / 2 - 25.4 / 2)
            xs.add(x + d / 2 + 25.4 / 2)
            ys.add(y - d / 2 - 25.4 / 2)
            ys.add(y + d / 2 + 25.4 / 2)

        size = max(max(xs) - min(xs), max(ys) - min(ys))  # in millimeters
        scale = IMAGE_SIZE / size

        for i in range(len(models)):
            x, y, d = models[i]
            models[i] = x * scale, y * scale, d * scale

        if text is None:
            neighbours = [[] for _ in range(N)]
            for i, a in enumerate(models):
                neighbours[i] = list(b for b in models if close(a, b, scale) and a != b)

        print(
            r"""\documentclass[varwidth]{standalone}
    % Make the PDF content reproducible by omitting time-/machine-based metadata: https://tex.stackexchange.com/a/313605
    \pdfinfoomitdate=1
    \pdftrailerid{}
    \pdfsuppressptexinfo=-1
    \usepackage{tikz}
    \usetikzlibrary{matrix, fit}
    \tikzset{every node/.style={font=\sffamily}}
    \begin{document}
              """,
            file=texfile,
        )
        if text is not None:
            print(text, file=texfile)
        else:
            print(r"\begin{tikzpicture}", file=texfile)
            print(
                rf"\draw[step={scale * 100},gray, thin] ({min(xs) * scale}, {min(ys) * scale}) grid ({max(xs) * scale}, {max(ys) * scale});"
            )
            if scale > 0.04:
                print(
                    rf"\draw[step={scale * 10},gray, very thin] ({min(xs) * scale}, {min(ys) * scale}) grid ({max(xs) * scale}, {max(ys) * scale});"
                )
            for i, m in enumerate(models):
                x, y, diam = m
                col = colours[i]
                print(
                    rf"\draw[fill={col}!10, semitransparent, draw={col}!20] ({x}, {y}) circle ({diam / 2 + 25.4 * scale});"
                )

            for i, a in enumerate(models):
                for b in neighbours[i]:
                    print(rf"\draw [blue] ({a[0]}, {a[1]})--({b[0]}, {b[1]});")

            for i, m in enumerate(models):
                x, y, diam = m
                colour = "black!20" if len(neighbours[i]) >= (1 + int(N > 6)) else "red!50"
                print(rf"\draw[fill={colour}, draw] ({x}, {y}) circle ({diam / 2});")

            print(r"\end{tikzpicture}", file=texfile)
        print(r"\end{document}", file=texfile)


main()
