#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<cmath>
//#include"Point.h"
using namespace std;
#define TWO_PI (2*M_PI)
struct Point{
char label; //for gnuplot.
int index; //rank. sort by heading.
double x, y; //coordinate.
double theta; //against base poit.
double heading( const Point& other) {
return atan2 ( y - this- > y, x - this- > x) ;
}
friend ostream& operator<< ( ostream& os, const Point& self) ;
} ;
ostream& operator<< ( ostream& os, const Point& self) {
os << self.label << ":" << "(" << self.x << ", " << self.y << ")" << ", " << self.index << ", " << self.theta ;
return os;
}
void show( vector< Point> & ps) {
for ( int i= 0 ; i< ps.size ( ) ; i++ ) {
cout << ps[ i] << endl;
}
}
bool cmp_coord( const Point& a, const Point& b) {
return a.y < b.y ? a.y < b.y : a.x < b.x ;
}
void func_index( vector< Point> & ps) {
for ( int i= 0 ; i< ps.size ( ) ; i++ ) {
ps[ i] .index = i;
}
}
//base point(ps[0])に対して角度順に整列されているかどうかを表示(可視化)するためのgpファイルを出力する。
void show_gp( vector< Point> & ps, char base[ ] ) {
cout << "set size square" << endl;
cout << "set nokey" << endl; //凡例を消す
for ( int i= 0 ; i< ps.size ( ) ; i++ ) {
printf ( "set label %d at %lf,%lf \" %c %d\" \n " , i+ 1 , ps[ i] .x , ps[ i] .y , ps[ i] .label , ps[ i] .index ) ;
}
printf ( "plot \" %s_gnuplot.dat\" \n " , base) ;
}
//base point(ps[0])に対する角度(偏角)を求める。また、それ自身(ps[0])同士の偏角も求めているものの、ゼロ除算は(どういうわけか)起こらない。
void func_theta( vector< Point> & ps, const Point base) {
for ( int i= 0 ; i< ps.size ( ) ; i++ ) {
ps[ i] .theta = atan2 ( ps[ i] .y - base.y , ps[ i] .x - base.x ) ;
}
}
bool cmp_theta( const Point& a, const Point& b) {
return a.theta < b.theta ;
}
bool is_counter_clock_wise( const Point& a, const Point& b, const Point& c) {
//return (b.x-a.x)*(c.y-a.y) - (b.x-a.y)*(c.x-a.x) < 0;
//return (b.x-a.x)*(c.y-a.y) - (a.x-b.y)*(c.x-b.x) < 0;
Point v;
v.x = a.x - b.x ;
v.y = a.y - b.y ;
Point w;
w.x = c.x - b.x ;
w.y = c.y - b.y ;
return v.x * w.y - w.x * v.y > 0 ;
}
void check_ccw( vector< Point> & ch, vector< Point> & internal) {
if ( is_counter_clock_wise( ch[ ch.size ( ) - 1 ] , ch[ ch.size ( ) - 2 ] , ch[ ch.size ( ) - 3 ] ) ) {
return ;
}
internal.push_back ( ch[ ch.size ( ) - 2 ] ) ;
ch.erase ( ch.end ( ) - 2 ) ;
return check_ccw( ch, internal) ;
}
vector< Point> get_convex_hull( vector< Point> & ps, vector< Point> & internal) {
vector< Point> ch;
for ( int i= 0 ; i< 3 ; i++ ) {
ch.push_back ( ps[ 0 ] ) ;
ps.erase ( ps.begin ( ) ) ;
}
while ( ! ps.empty ( ) ) {
ch.push_back ( ps[ 0 ] ) ;
ps.erase ( ps.begin ( ) ) ;
check_ccw( ch, internal) ;
}
return ch;
}
void output( vector< Point> & ps, char fn[ ] , bool is_closed) {
FILE * fp = fopen ( fn, "w" ) ;
for ( int i= 0 ; i< ps.size ( ) ; i++ ) {
fprintf ( fp, "%lf %lf\n " , ps[ i] .x , ps[ i] .y ) ;
}
if ( is_closed) {
fprintf ( fp, "%lf %lf\n " , ps[ 0 ] .x , ps[ 0 ] .y ) ;
}
fclose ( fp) ;
}
void show_ch( vector< Point> & ch, vector< Point> & internal, char base[ ] , bool is_png) {
if ( is_png) {
printf ( "set terminal png\n " ) ;
printf ( "set output \" %s.png\" \n " , base) ;
}
cout << "set size square" << endl;
cout << "set nokey" << endl; //凡例を消す
for ( int i= 0 ; i< internal.size ( ) ; i++ ) {
printf ( "set label %d at %lf,%lf \" %c %d\" \n " , i+ 1 , internal[ i] .x , internal[ i] .y , internal[ i] .label , internal[ i] .index ) ;
}
for ( int j= internal.size ( ) + 1 , i= 0 ; i< ch.size ( ) ; i++ , j++ ) {
printf ( "set label %d at %lf,%lf \" %c %d\" \n " , j+ 1 , ch[ i] .x , ch[ i] .y , ch[ i] .label , ch[ i] .index ) ;
}
char fn_int[ 256 ] ;
sprintf ( fn_int, "%s_internal.dat" , base) ;
char fn_ch[ 256 ] ;
sprintf ( fn_ch, "%s_convex_hull.dat" , base) ;
output( internal, fn_int, false ) ;
output( ch, fn_ch, true ) ;
printf ( "plot \" %s\" \n " , fn_int) ;
printf ( "plot \" %s\" with lines\n " , fn_ch) ;
}
int main( int argc, char * args[ ] ) {
////コマンドライン引数
if ( argc ! = 2 ) {
fprintf ( stderr , "arg error, argc=%d\n " , argc) ;
exit ( 1 ) ;
}
//graham [basename]
//graham data9
char base[ 256 ] ;
strcpy ( base, args[ 1 ] ) ;
////読み込み
int N;
cin >> N;
vector< Point> ps;
for ( int i= 0 ; i< N; i++ ) {
Point temp;
cin >> temp.label >> temp.x >> temp.y ;
temp.index = - 1 ;
temp.theta = 0 ;
ps.push_back ( temp) ;
}
//show(ps);//check, ok
//exit(0);//check, ok
////左下の探査(並び換え)
sort( ps.begin ( ) , ps.end ( ) , cmp_coord) ;
//show(ps);//check, ok
//exit(0);//check, ok
////角度による並び換え
func_theta( ps, ps[ 0 ] ) ;
sort( ps.begin ( ) , ps.end ( ) , cmp_theta) ;
func_index( ps) ;
//show(ps);//check, ok
//show_gp(ps, base);//check, ok
////凸包(convex hull)を求める
vector< Point> internal;
vector< Point> ch = get_convex_hull( ps, internal) ;
//show(ch);//check, ok
show_ch( ch, internal, base, false ) ;
return 0 ;
}
I2luY2x1ZGU8aW9zdHJlYW0+CiNpbmNsdWRlPHZlY3Rvcj4KI2luY2x1ZGU8c3RyaW5nPgojaW5jbHVkZTxhbGdvcml0aG0+CiNpbmNsdWRlPGNtYXRoPgovLyNpbmNsdWRlIlBvaW50LmgiCgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKI2RlZmluZSBUV09fUEkgKDIqTV9QSSkKCnN0cnVjdCBQb2ludHsKCWNoYXIgbGFiZWw7Ly9mb3IgZ251cGxvdC4KCWludCBpbmRleDsvL3JhbmsuIHNvcnQgYnkgaGVhZGluZy4KCWRvdWJsZSB4LCB5Oy8vY29vcmRpbmF0ZS4KCWRvdWJsZSB0aGV0YTsvL2FnYWluc3QgYmFzZSBwb2l0LgoJCglkb3VibGUgaGVhZGluZyhjb25zdCBQb2ludCYgb3RoZXIpewoJCXJldHVybiBhdGFuMih5IC0gdGhpcy0+eSwgeCAtIHRoaXMtPngpOwoJfQoJZnJpZW5kIG9zdHJlYW0mIG9wZXJhdG9yPDwob3N0cmVhbSYgb3MsIGNvbnN0IFBvaW50JiBzZWxmKTsKfTsKb3N0cmVhbSYgb3BlcmF0b3I8PChvc3RyZWFtJiBvcywgY29uc3QgUG9pbnQmIHNlbGYpewoJb3MgPDwgc2VsZi5sYWJlbCA8PCAiOiIgPDwgIigiIDw8IHNlbGYueCA8PCAiLCAiIDw8IHNlbGYueSA8PCAiKSIgPDwgIiwgIiA8PCBzZWxmLmluZGV4IDw8ICIsICIgPDwgc2VsZi50aGV0YTsKCXJldHVybiBvczsKfQoKdm9pZCBzaG93KHZlY3RvcjxQb2ludD4mIHBzKXsKCWZvcihpbnQgaT0wOyBpPHBzLnNpemUoKTsgaSsrKXsKCQljb3V0IDw8IHBzW2ldIDw8IGVuZGw7Cgl9Cn0KYm9vbCBjbXBfY29vcmQoY29uc3QgUG9pbnQmIGEsIGNvbnN0IFBvaW50JiBiKXsKCXJldHVybiBhLnkgPCBiLnkgPyBhLnkgPCBiLnkgOiBhLnggPCBiLng7Cn0Kdm9pZCBmdW5jX2luZGV4KHZlY3RvcjxQb2ludD4mIHBzKXsKCWZvcihpbnQgaT0wOyBpPHBzLnNpemUoKTsgaSsrKXsKCQlwc1tpXS5pbmRleCA9IGk7Cgl9Cn0KCgovL2Jhc2UgcG9pbnTvvIhwc1swXe+8ieOBq+WvvuOBl+OBpuinkuW6pumghuOBq+aVtOWIl+OBleOCjOOBpuOBhOOCi+OBi+OBqeOBhuOBi+OCkuihqOekuu+8iOWPr+imluWMlu+8ieOBmeOCi+OBn+OCgeOBrmdw44OV44Kh44Kk44Or44KS5Ye65Yqb44GZ44KL44CCCnZvaWQgc2hvd19ncCh2ZWN0b3I8UG9pbnQ+JiBwcywgY2hhciBiYXNlW10pewoJY291dCA8PCAic2V0IHNpemUgc3F1YXJlIiA8PCBlbmRsOwoJY291dCA8PCAic2V0IG5va2V5IiA8PCBlbmRsOy8v5Yeh5L6L44KS5raI44GZCgkKCWZvcihpbnQgaT0wOyBpPHBzLnNpemUoKTsgaSsrKXsKCQlwcmludGYoInNldCBsYWJlbCAlZCBhdCAlbGYsJWxmIFwiJWMgJWRcIlxuIiwgaSsxLCBwc1tpXS54LCBwc1tpXS55LCBwc1tpXS5sYWJlbCwgcHNbaV0uaW5kZXgpOwoJfQoJCglwcmludGYoInBsb3QgXCIlc19nbnVwbG90LmRhdFwiXG4iLCBiYXNlKTsKfQoKLy9iYXNlIHBvaW5077yIcHNbMF3vvInjgavlr77jgZnjgovop5LluqbvvIjlgY/op5LvvInjgpLmsYLjgoHjgovjgILjgb7jgZ/jgIHjgZ3jgozoh6rouqvvvIhwc1swXe+8ieWQjOWjq+OBruWBj+inkuOCguaxguOCgeOBpuOBhOOCi+OCguOBruOBruOAgeOCvOODremZpOeul+OBr++8iOOBqeOBhuOBhOOBhuOCj+OBkeOBi++8iei1t+OBk+OCieOBquOBhOOAggp2b2lkIGZ1bmNfdGhldGEodmVjdG9yPFBvaW50PiYgcHMsIGNvbnN0IFBvaW50IGJhc2UpewoJZm9yKGludCBpPTA7IGk8cHMuc2l6ZSgpOyBpKyspewoJCXBzW2ldLnRoZXRhID0gYXRhbjIocHNbaV0ueSAtIGJhc2UueSwgcHNbaV0ueCAtIGJhc2UueCk7Cgl9Cn0KYm9vbCBjbXBfdGhldGEoY29uc3QgUG9pbnQmIGEsIGNvbnN0IFBvaW50JiBiKXsKCXJldHVybiBhLnRoZXRhIDwgYi50aGV0YTsKfQpib29sIGlzX2NvdW50ZXJfY2xvY2tfd2lzZShjb25zdCBQb2ludCYgYSwgY29uc3QgUG9pbnQmIGIsIGNvbnN0IFBvaW50JiBjKXsKCS8vcmV0dXJuIChiLngtYS54KSooYy55LWEueSkgLSAoYi54LWEueSkqKGMueC1hLngpIDwgMDsKCS8vcmV0dXJuIChiLngtYS54KSooYy55LWEueSkgLSAoYS54LWIueSkqKGMueC1iLngpIDwgMDsKCVBvaW50IHY7Cgl2LnggPSBhLnggLSBiLng7Cgl2LnkgPSBhLnkgLSBiLnk7CgkKCVBvaW50IHc7Cgl3LnggPSBjLnggLSBiLng7Cgl3LnkgPSBjLnkgLSBiLnk7CgkKCXJldHVybiB2Lngqdy55IC0gdy54KnYueSA+IDA7Cn0Kdm9pZCBjaGVja19jY3codmVjdG9yPFBvaW50PiYgY2gsIHZlY3RvcjxQb2ludD4mIGludGVybmFsKXsKCWlmKGlzX2NvdW50ZXJfY2xvY2tfd2lzZShjaFtjaC5zaXplKCktMV0sIGNoW2NoLnNpemUoKS0yXSwgY2hbY2guc2l6ZSgpLTNdKSl7CgkJcmV0dXJuOwoJfQoJCglpbnRlcm5hbC5wdXNoX2JhY2soY2hbY2guc2l6ZSgpLTJdKTsKCWNoLmVyYXNlKGNoLmVuZCgpLTIpOwoJcmV0dXJuIGNoZWNrX2NjdyhjaCwgaW50ZXJuYWwpOwp9CnZlY3RvcjxQb2ludD4gZ2V0X2NvbnZleF9odWxsKHZlY3RvcjxQb2ludD4mIHBzLCB2ZWN0b3I8UG9pbnQ+JiBpbnRlcm5hbCl7Cgl2ZWN0b3I8UG9pbnQ+IGNoOwoJCglmb3IoaW50IGk9MDsgaTwzOyBpKyspewoJCWNoLnB1c2hfYmFjayhwc1swXSk7CgkJcHMuZXJhc2UocHMuYmVnaW4oKSk7Cgl9CgkKCXdoaWxlKCFwcy5lbXB0eSgpKXsKCQljaC5wdXNoX2JhY2socHNbMF0pOwoJCXBzLmVyYXNlKHBzLmJlZ2luKCkpOwoJCWNoZWNrX2NjdyhjaCwgaW50ZXJuYWwpOwoJfQoJCglyZXR1cm4gY2g7Cn0Kdm9pZCBvdXRwdXQodmVjdG9yPFBvaW50PiYgcHMsIGNoYXIgZm5bXSwgYm9vbCBpc19jbG9zZWQpewoJRklMRSogZnAgPSBmb3BlbihmbiwgInciKTsKCWZvcihpbnQgaT0wOyBpPHBzLnNpemUoKTsgaSsrKXsKCQlmcHJpbnRmKGZwLCAiJWxmICVsZlxuIiwgcHNbaV0ueCwgcHNbaV0ueSk7Cgl9CglpZihpc19jbG9zZWQpewoJCWZwcmludGYoZnAsICIlbGYgJWxmXG4iLCBwc1swXS54LCBwc1swXS55KTsKCX0KCWZjbG9zZShmcCk7Cn0Kdm9pZCBzaG93X2NoKHZlY3RvcjxQb2ludD4mIGNoLCB2ZWN0b3I8UG9pbnQ+JiBpbnRlcm5hbCwgY2hhciBiYXNlW10sIGJvb2wgaXNfcG5nKXsKCWlmKGlzX3BuZyl7CgkJcHJpbnRmKCJzZXQgdGVybWluYWwgcG5nXG4iKTsKCQlwcmludGYoInNldCBvdXRwdXQgXCIlcy5wbmdcIlxuIiwgYmFzZSk7Cgl9CgkKCWNvdXQgPDwgInNldCBzaXplIHNxdWFyZSIgPDwgZW5kbDsKCWNvdXQgPDwgInNldCBub2tleSIgPDwgZW5kbDsvL+WHoeS+i+OCkua2iOOBmQoJCglmb3IoaW50IGk9MDsgaTxpbnRlcm5hbC5zaXplKCk7IGkrKyl7CgkJcHJpbnRmKCJzZXQgbGFiZWwgJWQgYXQgJWxmLCVsZiBcIiVjICVkXCJcbiIsIGkrMSwgaW50ZXJuYWxbaV0ueCwgaW50ZXJuYWxbaV0ueSwgaW50ZXJuYWxbaV0ubGFiZWwsIGludGVybmFsW2ldLmluZGV4KTsKCX0KCWZvcihpbnQgaj1pbnRlcm5hbC5zaXplKCkrMSwgaT0wOyBpPGNoLnNpemUoKTsgaSsrLCBqKyspewoJCXByaW50Zigic2V0IGxhYmVsICVkIGF0ICVsZiwlbGYgXCIlYyAlZFwiXG4iLCBqKzEsIGNoW2ldLngsIGNoW2ldLnksIGNoW2ldLmxhYmVsLCBjaFtpXS5pbmRleCk7Cgl9CgkKCWNoYXIgZm5faW50WzI1Nl07CglzcHJpbnRmKGZuX2ludCwgIiVzX2ludGVybmFsLmRhdCIsIGJhc2UpOwoJY2hhciBmbl9jaFsyNTZdOwoJc3ByaW50Zihmbl9jaCwgIiVzX2NvbnZleF9odWxsLmRhdCIsIGJhc2UpOwoJCglvdXRwdXQoaW50ZXJuYWwsIGZuX2ludCwgZmFsc2UpOwoJb3V0cHV0KGNoLCBmbl9jaCwgdHJ1ZSk7CgkKCXByaW50ZigicGxvdCBcIiVzXCJcbiIsIGZuX2ludCk7CglwcmludGYoInBsb3QgXCIlc1wiIHdpdGggbGluZXNcbiIsIGZuX2NoKTsKfQppbnQgbWFpbihpbnQgYXJnYywgY2hhciogYXJnc1tdKXsKCS8vLy/jgrPjg57jg7Pjg4njg6njgqTjg7PlvJXmlbAKCWlmKGFyZ2MgIT0gMil7CgkJZnByaW50ZihzdGRlcnIsICJhcmcgZXJyb3IsIGFyZ2M9JWRcbiIsIGFyZ2MpOwoJCWV4aXQoMSk7Cgl9CgkvL2dyYWhhbSBbYmFzZW5hbWVdCgkvL2dyYWhhbSBkYXRhOQoJCgljaGFyIGJhc2VbMjU2XTsKCXN0cmNweShiYXNlLCBhcmdzWzFdKTsKCQoJCgkvLy8v6Kqt44G/6L6844G/CglpbnQgTjsKCWNpbiA+PiBOOwoJCgl2ZWN0b3I8UG9pbnQ+IHBzOwoJCglmb3IoaW50IGk9MDsgaTxOOyBpKyspewoJCVBvaW50IHRlbXA7CgkJY2luID4+IHRlbXAubGFiZWwgPj4gdGVtcC54ID4+IHRlbXAueTsKCQl0ZW1wLmluZGV4ID0gLTE7CgkJdGVtcC50aGV0YSA9IDA7CgkJcHMucHVzaF9iYWNrKHRlbXApOwoJfQoJLy9zaG93KHBzKTsvL2NoZWNrLCBvawoJLy9leGl0KDApOy8vY2hlY2ssIG9rCgkKCQoJLy8vL+W3puS4i+OBruaOouafu++8iOS4puOBs+aPm+OBiO+8iQoJc29ydChwcy5iZWdpbigpLCBwcy5lbmQoKSwgY21wX2Nvb3JkKTsKCS8vc2hvdyhwcyk7Ly9jaGVjaywgb2sKCS8vZXhpdCgwKTsvL2NoZWNrLCBvawoJCgkKCS8vLy/op5LluqbjgavjgojjgovkuKbjgbPmj5vjgYgKCWZ1bmNfdGhldGEocHMsIHBzWzBdKTsKCXNvcnQocHMuYmVnaW4oKSwgcHMuZW5kKCksIGNtcF90aGV0YSk7CglmdW5jX2luZGV4KHBzKTsKCS8vc2hvdyhwcyk7Ly9jaGVjaywgb2sKCS8vc2hvd19ncChwcywgYmFzZSk7Ly9jaGVjaywgb2sKCQoJCgkvLy8v5Ye45YyF77yIY29udmV4IGh1bGzvvInjgpLmsYLjgoHjgosKCXZlY3RvcjxQb2ludD4gaW50ZXJuYWw7Cgl2ZWN0b3I8UG9pbnQ+IGNoID0gZ2V0X2NvbnZleF9odWxsKHBzLCBpbnRlcm5hbCk7CgkvL3Nob3coY2gpOy8vY2hlY2ssIG9rCglzaG93X2NoKGNoLCBpbnRlcm5hbCwgYmFzZSwgZmFsc2UpOwoJCglyZXR1cm4gMDsKfQo=