fork(1) download
  1. // line_symmetry.cpp --- 多角形が線対称かどうか判定する。
  2. // Copyright (C) 2013 片山博文MZ. All rights reserved.
  3. #include <iostream>
  4. #include <vector>
  5. #include <cstdlib>
  6. #include <cstring>
  7. #include <cmath>
  8. using namespace std;
  9.  
  10. // 実数型。
  11. typedef double numeric_t;
  12.  
  13. // 位置ベクトルの比較の際の許容される誤差。
  14. const numeric_t TOLERANCE1 = 0.25;
  15.  
  16. // 単位ベクトルの比較の際の許容される誤差。
  17. const numeric_t TOLERANCE2 = 0.015625;
  18.  
  19. // 平面ベクトル。
  20. class Point2D
  21. {
  22. public:
  23. numeric_t m_x, m_y;
  24.  
  25. public:
  26. Point2D()
  27. {
  28. }
  29. Point2D(numeric_t x, numeric_t y) : m_x(x), m_y(y)
  30. {
  31. }
  32. Point2D(const Point2D& p) : m_x(p.m_x), m_y(p.m_y)
  33. {
  34. }
  35.  
  36. void GetXY(numeric_t& x, numeric_t& y) const
  37. {
  38. x = m_x; y = m_y;
  39. }
  40. void SetXY(numeric_t x, numeric_t y)
  41. {
  42. m_x = x; m_y = y;
  43. }
  44. bool IsZero() const
  45. {
  46. return Length() <= TOLERANCE1;
  47. }
  48. void SetZero()
  49. {
  50. m_x = m_y = 0;
  51. }
  52.  
  53. // 長さ。
  54. numeric_t Length() const
  55. {
  56. return sqrt(m_x * m_x + m_y * m_y);
  57. }
  58. // 垂直なベクトル。
  59. Point2D Perpendicular() const
  60. {
  61. return Point2D(m_y, -m_x);
  62. }
  63. // 単位ベクトル。
  64. Point2D Unit() const
  65. {
  66. return *this / Length();
  67. }
  68.  
  69. Point2D& operator=(const Point2D& p)
  70. {
  71. m_x = p.m_x; m_y = p.m_y;
  72. return *this;
  73. }
  74. Point2D& operator+=(const Point2D& p)
  75. {
  76. m_x += p.m_x; m_y += p.m_y;
  77. return *this;
  78. }
  79. Point2D& operator-=(const Point2D& p)
  80. {
  81. m_x -= p.m_x; m_y -= p.m_y;
  82. return *this;
  83. }
  84. Point2D& operator*=(numeric_t d)
  85. {
  86. m_x *= d; m_y *= d;
  87. return *this;
  88. }
  89. Point2D& operator/=(numeric_t d)
  90. {
  91. m_x /= d; m_y /= d;
  92. return *this;
  93. }
  94.  
  95. friend Point2D operator+(const Point2D& p1, const Point2D& p2)
  96. {
  97. Point2D p(p1);
  98. p += p2;
  99. return p;
  100. }
  101. friend Point2D operator-(const Point2D& p1, const Point2D& p2)
  102. {
  103. Point2D p(p1);
  104. p -= p2;
  105. return p;
  106. }
  107.  
  108. friend bool operator==(const Point2D& p1, const Point2D& p2)
  109. {
  110. numeric_t dx = p2.m_x - p1.m_x, dy = p2.m_y - p1.m_y;
  111. return sqrt(dx * dx + dy * dy) <= TOLERANCE1;
  112. }
  113. friend bool operator!=(const Point2D& p1, const Point2D& p2)
  114. {
  115. return !(p1 == p2);
  116. }
  117.  
  118. friend numeric_t operator*(const Point2D& p1, const Point2D& p2)
  119. {
  120. return p1.m_x * p2.m_x + p1.m_y * p2.m_y;
  121. }
  122.  
  123. friend Point2D operator*(const Point2D& p1, numeric_t d)
  124. {
  125. Point2D p(p1);
  126. p *= d;
  127. return p;
  128. }
  129. friend Point2D operator/(const Point2D& p1, numeric_t d)
  130. {
  131. Point2D p(p1);
  132. p /= d;
  133. return p;
  134. }
  135. friend Point2D operator*(numeric_t d, const Point2D& p1)
  136. {
  137. return p1 * d;
  138. }
  139.  
  140. // 中点。
  141. friend Point2D MidPoint(const Point2D& p1, const Point2D& p2)
  142. {
  143. return Point2D((p1.m_x + p2.m_x) / 2, (p1.m_y + p2.m_y) / 2);
  144. }
  145.  
  146. friend ostream& operator<<(ostream& o, const Point2D& p)
  147. {
  148. o << "(" << p.m_x << ", " << p.m_y << ")";
  149. return o;
  150. }
  151.  
  152. // 一直線上にあるかどうか?
  153. friend bool OnOneLine(const Point2D& p1, const Point2D& p2, const Point2D& p3)
  154. {
  155. return ((p2 - p1).Unit() - (p3 - p2).Unit()).Length() <= TOLERANCE2;
  156. }
  157. };
  158.  
  159. int main(void)
  160. {
  161. int i, j, n, i1, i2;
  162. numeric_t x, y, g;
  163. Point2D mp, unit, p1, p2, p3, q, r;
  164. vector<Point2D> polygon;
  165. bool f;
  166.  
  167. // 入力。
  168. cout << "多角形の頂点の個数: ";
  169. cin >> n;
  170. if (n < 0)
  171. {
  172. cout << "データが不正です。" << endl;
  173. return 1;
  174. }
  175. for (i = 0; i < n; i++)
  176. {
  177. cout << "頂点#" << (i + 1) << "のx座標とy座標: ";
  178. cin >> x >> y;
  179. polygon.push_back(Point2D(x, y));
  180. }
  181.  
  182. // 重複した頂点を取り除く。
  183. f = false;
  184. for (i = 0; i < n - 1; i++)
  185. {
  186. p1 = polygon[i];
  187. p2 = polygon[i + 1];
  188. if (p1 == p2)
  189. {
  190. memmove(&polygon[i], &polygon[i + 1], (n - i - 1) * sizeof(Point2D));
  191. polygon.resize(--n);
  192. i--;
  193. f = true;
  194. }
  195. }
  196. if (n > 1)
  197. {
  198. p1 = polygon[n - 1];
  199. p2 = polygon[0];
  200. if (p1 == p2)
  201. {
  202. polygon.resize(--n);
  203. f = true;
  204. }
  205. }
  206. if (f)
  207. cout << "重複した頂点を取り除きました。" << endl;
  208.  
  209. // 約180度の角の頂点を取り除く。
  210. f = false;
  211. for (i = 0; i < n - 2; i++)
  212. {
  213. p1 = polygon[i];
  214. p2 = polygon[i + 1];
  215. p3 = polygon[i + 2];
  216. if (OnOneLine(p1, p2, p3))
  217. {
  218. memmove(&polygon[i + 1], &polygon[i + 2], (n - i - 2) * sizeof(Point2D));
  219. polygon.resize(--n);
  220. i--;
  221. f = true;
  222. }
  223. }
  224. while (n > 2)
  225. {
  226. p1 = polygon[n - 2];
  227. p2 = polygon[n - 1];
  228. p3 = polygon[0];
  229. if (OnOneLine(p1, p2, p3))
  230. {
  231. polygon.resize(--n);
  232. f = true;
  233. continue;
  234. }
  235. break;
  236. }
  237. while (n > 2)
  238. {
  239. p1 = polygon[n - 1];
  240. p2 = polygon[0];
  241. p3 = polygon[1];
  242. if (OnOneLine(p1, p2, p3))
  243. {
  244. memmove(&polygon[0], &polygon[1], (n - 1) * sizeof(Point2D));
  245. polygon.resize(--n);
  246. f = true;
  247. continue;
  248. }
  249. break;
  250. }
  251. if (f)
  252. cout << "約180度の角の頂点を取り除きました。" << endl;
  253.  
  254. // 表示。
  255. if (n > 0)
  256. {
  257. for (i = 0; i < n; i++)
  258. {
  259. cout << "頂点#" << (i + 1) << ": " << polygon[i] << endl;
  260. }
  261. }
  262. else
  263. {
  264. cout << "頂点はありません。" << endl;
  265. }
  266.  
  267. // 0角形、1角形、2角形は、常に線対称。
  268. if (n <= 2)
  269. {
  270. cout << "頂点が2個以下なので線対称です。" << endl;
  271. return 0;
  272. }
  273.  
  274. // 頂点の角の二等分線が対称の軸か?
  275. for (i = 0; i < n; i++)
  276. {
  277. // 隣り合う3頂点。
  278. p1 = polygon[(i - 1 + n) % n];
  279. p2 = polygon[i];
  280. p3 = polygon[(i + 1) % n];
  281.  
  282. // 角に隣り合う2辺の長さが等しいか?
  283. if (fabs((p2 - p1).Length() - (p3 - p2).Length()) <= TOLERANCE1)
  284. {
  285. // 角に隣り合う2頂点の中点。
  286. mp = MidPoint(p1, p3);
  287.  
  288. // 角の二等分線に平行な単位ベクトル。
  289. if ((mp - p2).IsZero())
  290. unit = (p3 - p1).Perpendicular().Unit();
  291. else
  292. unit = (mp - p2).Unit();
  293.  
  294. f = true;
  295. for (j = 1; j <= n / 2; j++)
  296. {
  297. // 対称か判定する2頂点のインデックス。
  298. i1 = (i - j + n) % n;
  299. i2 = (i + j) % n;
  300.  
  301. g = (polygon[i1] - mp) * unit; // 中点から垂線までの長さ。
  302. q = mp + unit * g; // 対称の軸上の点(垂線と交わる)。
  303. r = q - (polygon[i1] - q); // 軸に対して対称な位置。
  304. //cout << "1%%" << (r - polygon[i2]).Length() << endl;
  305. if (r != polygon[i2])
  306. {
  307. f = false;
  308. break;
  309. }
  310. }
  311.  
  312. if (f)
  313. {
  314. cout << "頂点#" << (i + 1) << "で線対称です。" << endl;
  315. return 0;
  316. }
  317. }
  318. }
  319.  
  320. // 辺の垂直二等分線が対称の軸か?
  321. for (i = 0; i < n; i++)
  322. {
  323. // 隣り合う2頂点。
  324. p1 = polygon[i];
  325. p2 = polygon[(i + 1) % n];
  326.  
  327. // 辺の中点。
  328. mp = MidPoint(p1, p2);
  329.  
  330. // 辺に対する垂直単位ベクトル。
  331. if ((p2 - p1).Perpendicular().IsZero())
  332. unit.SetZero();
  333. else
  334. unit = (p2 - p1).Perpendicular().Unit();
  335.  
  336. f = true;
  337. for (j = 1; j < (n + 1) / 2; j++)
  338. {
  339. // 対称か判定する2頂点のインデックス。
  340. i1 = (i - j + n) % n;
  341. i2 = (i + j + 1) % n;
  342.  
  343. g = (polygon[i1] - mp) * unit; // 中点から垂線までの長さ。
  344. q = mp + unit * g; // 対称の軸上の点(垂線と交わる)。
  345. r = q - (polygon[i1] - q); // 軸に対して対称な位置。
  346. //cout << "2%%" << (r - polygon[i2]).Length() << endl;
  347. if (r != polygon[i2])
  348. {
  349. f = false;
  350. break;
  351. }
  352. }
  353.  
  354. if (f)
  355. {
  356. cout << "頂点#" << (i + 1) << "と頂点#" << ((i + 1) % n + 1) <<
  357. "の間で線対称です。" << endl;
  358. return 0;
  359. }
  360. }
  361.  
  362. cout << "線対称ではありません。" << endl;
  363. return 0;
  364. }
Runtime error #stdin #stdout 0s 2864KB
stdin
Standard input is empty
stdout
多角形の頂点の個数: データが不正です。