簡単に点から円への接点を求める

方程式を解いて求めるのでは面倒なので、幾何的に求めます。

#準備
点を表す構造体Vec2と円を表す構造体Circleを作ります。

<details>
<summary>コードをクリックで展開</summary>
<div>

```cpp
namespace geometry {
	
	constexpr double EPS = 1e-12;

	struct Vec2 {
		double x, y;

		Vec2() = default;
		constexpr Vec2(double _x, double _y) :x(_x), y(_y) {}
		explicit Vec2(double arg) : x(cos(arg)), y(sin(arg)) {}

		bool operator>(const Vec2& v) const {
			if (!(fabs(x - v.x) <= EPS)) return x > v.x;
			return y > v.y;
		}

		constexpr Vec2 operator+(const Vec2& v) const { return { x + v.x,y + v.y }; }
		constexpr Vec2 operator-(const Vec2& v) const { return { x - v.x,y - v.y }; }

		double length() const {
			return hypot(x, y);
		}
		double distanceFrom(const Vec2& v) const {
			return (v - *this).length();
		}

		double angle() const { return atan2(y, x); }

		constexpr friend Vec2 operator*(double s, const Vec2& v) {
			return { s * v.x,s * v.y };
		}
		friend std::istream& operator>>(std::istream& is, Vec2& rhs) {
			return is >> rhs.x >> rhs.y;
		}
	};

	struct Circle {
		Vec2 center;
		double r;

		Circle() = default;
		constexpr Circle(const Vec2& _center, double _r) :center(_center), r(_r) {}

		friend std::istream& operator>>(std::istream& is, Circle& rhs) {
			return is >> rhs.center >> rhs.r;
		}
	};
}
```

</div>
</details>


#接点の数
円と点の位置関係によって3つに分けられます。

- 点が円の外側: 接点は2つ
- 点が円周上: 　接点は1つ
- 点が円の内側: 接点は存在しない

![キャプチャ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493938/8c657788-db6f-2c8e-b4a4-ccc363cffe8f.png)

#点が円の外側の場合
![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493938/e58c0a9a-45d1-5d1c-5d18-be92a1128e73.png)
上図より、2つの接点はそれぞれ$$O+r(\cos(\theta_1+\theta_2),\sin(\theta_1+\theta_2))$$$$O+r(\cos(\theta_1-\theta_2),\sin(\theta_1-\theta_2))$$となるので、$\theta_1$と$\theta_2$が求められれば良いです。

- $\theta_1$: atan2を使うことで求められます。
- $\theta_2$: $\angle OHA=90^\circ$なので、$$\theta_2=\cos^{-1}\frac{r}{d_1}$$となります。

#点が円周上の場合
点$A$をそのまま返せば良いです。
#点が円の内側の場合
接点は存在しません。今回はstd::nulloptを返します。

#コード

<details>
<summary>コードをクリックで展開</summary>
<div>

```cpp
namespace geometry {
	
	constexpr double EPS = 1e-12;

	struct Vec2 {
		double x, y;

		Vec2() = default;
		constexpr Vec2(double _x, double _y) :x(_x), y(_y) {}
		explicit Vec2(double arg) : x(cos(arg)), y(sin(arg)) {}

		bool operator>(const Vec2& v) const {
			if (!(fabs(x - v.x) <= EPS)) return x > v.x;
			return y > v.y;
		}

		constexpr Vec2 operator+(const Vec2& v) const { return { x + v.x,y + v.y }; }
		constexpr Vec2 operator-(const Vec2& v) const { return { x - v.x,y - v.y }; }

		double length() const {
			return hypot(x, y);
		}
		double distanceFrom(const Vec2& v) const {
			return (v - *this).length();
		}

		double angle() const { return atan2(y, x); }

		constexpr friend Vec2 operator*(double s, const Vec2& v) {
			return { s * v.x,s * v.y };
		}
		friend std::istream& operator>>(std::istream& is, Vec2& rhs) {
			return is >> rhs.x >> rhs.y;
		}
	};

	struct Circle {
		Vec2 center;
		double r;

		Circle() = default;
		constexpr Circle(const Vec2& _center, double _r) :center(_center), r(_r) {}

		std::optional<std::vector<Vec2>> tangentPointFrom(const Vec2& v) const {
			const double
				d1 = center.distanceFrom(v),
				d2 = d1 * d1 - r * r;

			if (d2 + EPS < 0) return std::nullopt;
			if (fabs(d2) <= EPS) return std::vector<Vec2>{v};

			const double
				theta1 = (v - center).angle(),
				theta2 = acos(r / d1);

			std::vector<Vec2>res;
			res.emplace_back(center + r * Vec2(theta1 + theta2));
			res.emplace_back(center + r * Vec2(theta1 - theta2));

			if (res[0] > res[1]) std::swap(res[0], res[1]);

			return res;
		}

		friend std::istream& operator>>(std::istream& is, Circle& rhs) {
			return is >> rhs.center >> rhs.r;
		}
	};
}
```

</div>
</details>

使用例: [AOJ 円の接線](https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/all/CGL_7_F) [提出](https://onlinejudge.u-aizu.ac.jp/solutions/problem/CGL_7_F/review/4882913/EbiShu0309/C++17)