#include <stdio.h>
#include <algorithm>
#include <unordered_map>
#include <set>
#include <memory>
#include <atomic>
#include <thread>
#include <list>
#include "zlist.h"
#include "line.h"
#include "ant.h"
#include "config_file.h"
#include "card_path.h"
#include "visit.h"

namespace{

inline bool eq(double a,double b,double e=0.0001)
{
	return fabs(a-b)<e;
}

struct vertex:point
{
	float level;
	int sid0,sid1;
	vertex()
		:level(0)
		,sid0(0)
		,sid1(0)
	{}

	vertex(const point&pt,float level_=0,int site_id0=0,int site_id1=0)
		:point(pt)
		,level(level_)
		,sid0(site_id0)
		,sid1(site_id1)
	{
	}

	std::string to_string()const
	{
		char buf[128];
		sprintf(buf,"%.2f,%.3lf,%d,%d,%.2lf",x,y,sid0,sid1,level/PI*180);

		return buf;
	}
};

struct vertex_list;
struct base_path:std::array<int,2>
{
	int sid;
	base_path(int i1=-1,int i2=-1,int _sid=0)
	{
		at(0)=i1;
		at(1)=i2;
		sid=_sid;
	}

	bool operator<(const base_path&o)const
	{
		int c=at(0)-o.at(0);
		if(c!=0)
			return c<0;

		return at(1)-o.at(1)<0;
	}

	point  cross(const vertex_list&v_list, const base_path&o)const;
	bool   contains(const vertex_list&v_list, const point&o, double e)const;
	double arg(const vertex_list&v)const;
	int    type(const vertex_list&v)const;
	line_v as_line(const vertex_list&v)const;
	int    level(const vertex_list&v)const;
};

struct vertex_list
{
	std::vector<vertex> v;

	std::string to_string()const
	{
		std::string ret;
		ret.reserve(1024);

		char buf[128];
		for(int i=0,len=v.size();i<len;i++)
		{
			sprintf(buf,"vertex:%3d,%s\n",i,v[i].to_string().c_str());

			ret+=buf;
		}

		return std::move(ret);
	}

	void log()
	{
		log_info("%s",to_string().c_str());
	}

	static unsigned hash(const point&p)
	{
		return (((((unsigned)p.x)>>2)<<16) + (((unsigned)p.y)>>2));
	}

	int find(const point&p,double x=0.01)const
	{
		int rc=-1;
		double t;

		for(int i=0,len=v.size();i<len;i++)
		{
			t=p.dist(v[i]);
			if(t<x)
			{
				rc=i;
				x=t;
			}
		}

		return rc;
	}

	int add(const point&p,float level=0,int sid0=0,int sid1=0)
	{
		int i=find(p);

		if(i<0)
		{
			v.push_back(vertex(p,level,sid0,sid1));
			return v.size()-1;
		}

		vertex&v0=v[i];

		v0.level=std::max(v0.level,level);

		return i;
	}

	int size()const
	{
		return v.size();
	}

	const vertex&operator[](int i)const
	{
		return v[i];
	}

	vertex&operator[](int i)
	{
		return v[i];
	}
};

int base_path::level(const vertex_list&v)const
{
	const vertex&p0=v[at(0)];
	const vertex&p1=v[at(1)];

	return p0.level+p1.level;
}

line_v base_path::as_line(const vertex_list&v)const
{
	const vertex&p0=v[at(0)];
	const vertex&p1=v[at(1)];

	return line_v(p0,p1);
}

double  base_path::arg(const vertex_list&v)const
{
	return as_line(v).arg();
}

bool  base_path::contains(const vertex_list&v, const point&o, double e)const
{
	return as_line(v).contain(o,e);
}

point  base_path::cross(const vertex_list&v, const base_path&o)const
{
	line_v l0=as_line(v);
	line_v l1=o.as_line(v);

	return l0.crossing(l1);
}

void log_path(const std::vector<base_path>&path,const vertex_list&v_list,const char*add_info="")
{
	log_info("%s\n","----------------------------------------------------------------");
	for(int i=0,len=path.size();i<len;i++)
	{
		double c=path[i].arg(v_list)/PI*180;
		log_info("base_path:%s %.6lf, %03d,(%d,%s),(%d,%s)",add_info,c,i,path[i][0],v_list[path[i][0]].to_string().c_str(),path[i][1],v_list[path[i][1]].to_string().c_str());
	}
}

struct handle_path :visitor<std::shared_ptr<site>>
{
	std::vector<base_path> ret;
	vertex_list v;
	handle_path()
	{
		v.add(point(0,0),0,-1);
	}
	bool visit(std::shared_ptr<site> sit)
	{
		//auto&s=sites[i];
		const auto &s = *sit;

		if(!s.have_valid_path())
			return false;

		if(s.path(0).empty()||s.path(1).empty())
			return false;
        if(s[0].size()<2)
			return false;
        line_v l000 = s[0][0][0]; //天线->分站天线路径集合->路径
        line_v l010 = s[0][1][0];
        if(l000.is_same(l010))
        {
			int p0=v.add(point::min(s.path(0),s.path(1)),0,s.m_id);
			int p1=v.add(point::max(s.path(0),s.path(1)),0,s.m_id);

		    ret.push_back(base_path(p0,p1));
			ret.back().sid=s.m_id;
        }
        else
        {
            point px = l000.line::crossing(l010);
            for(int i=0;i<2;i++)
            {
			    int p0=v.add(point::min(px,s.path(i)),0,s.m_id);
			    int p1=v.add(point::max(px,s.path(i)),0,s.m_id);

		        ret.push_back(base_path(p0,p1));
			    ret.back().sid=s.m_id;
            }
        }
        for(int i=0;i<2;i++)
        {
            if(!s[0][i][1].empty())
            {
			    int p0=v.add(point::min(s[0][i][1][0],s[0][i][1][1]),0,s.m_id);
			    int p1=v.add(point::max(s[0][i][1][0],s[0][i][1][1]),0,s.m_id);

		        ret.push_back(base_path(p0,p1));
			    ret.back().sid=s.m_id;
            }
        }
		return true;
	}
};
static std::vector<base_path> init_path(std::vector<base_path> & ret,vertex_list&v)
{
	do
	{
		config_file cfg;
		if(cfg.open("../etc/path-not-cross.ini"))
			break;

		auto kset=cfg.keys();
		if(kset.empty())
			break;

		for(auto k:kset)
		{
			if(strncmp(k,"add_path",8)!=0)
				continue;

			const char* vv=cfg.get(k,"");

			point p0;
			point p1;
			if(sscanf(vv,"%lf,%lf,%lf,%lf",&p0.x,&p0.y,&p1.x,&p1.y)==4)
			{
				point p_0=point::min(p0,p1);
				point p_1=point::max(p0,p1);
				int p00=v.add(p_0,0,0);
				int p10=v.add(p_1,0,0);

				ret.push_back(base_path(p00,p10,0));
			}
		}
		break;
	}while(1);

	auto remove_dup=[](std::vector<base_path>&ret){
		std::sort(ret.begin(),ret.end());
		ret.erase(std::unique(ret.begin(),ret.end()),ret.end());
	};

	auto remove_empty=[](std::vector<base_path>&ret,vertex_list&v){
		ret.erase(std::remove_if(ret.begin(),ret.end(),[&v](base_path&p){
						point&p0=v[p[0]];
						point&p1=v[p[1]];
						return p0.dist(p1)<.00001;
						}),
					ret.end());
	};

	auto sort_path=[](std::vector<base_path> & ret,vertex_list&v){
		std::sort(ret.begin(),ret.end(),[&v](const base_path&p1,const base_path&p2){
				return point::min(v[p1[0]],v[p1[1]]) < point::min(v[p2[0]],v[p2[1]]);
		});
	};

	remove_dup(ret);
	sort_path(ret,v);
	log_path(ret,v,"合并前");
	//合并相同
	for(int i=0,len=ret.size();i<len;i++)
	{
		line_v li=ret[i].as_line(v);
		for(int j=i+1;j<len;j++)
		{
			line_v lj=ret[j].as_line(v);
			if(!lj.is_same(li,1)) //li线段两个点在lj直线上
				continue;
			line_v ij=lj.projection(li);//重叠

			if(ij.empty()&&ij[0].empty()&&ij[0].empty())
				continue;			

			point p0=li.as_line().projection(v[ret[j][0]]);
			point p1=li.as_line().projection(v[ret[j][1]]);

			p0=point::min(p0,v[ret[i][0]]);
			p1=point::max(p1,v[ret[i][1]]);

			ret[j][0]=v.add(p0,0);
			ret[j][1]=v.add(p1,0);

			ret[i][0]=0;
			ret[i][1]=0;
			break;
		}
	}

	ret.erase(std::remove_if(ret.begin(),ret.end(),[&v](const base_path&p){
		return p[0]==0||p[1]==0;
	}),ret.end());

	sort_path(ret,v);
	log_path(ret,v,"合并后");

	//非路径交点配置
	std::vector<point> no_cross;
	auto in_no_cross=[&no_cross](const point&pt){
		for(auto p:no_cross)
		{
			if(p.dist(pt)<3)
				return true;
		}

		return false;
	};

	do
	{
		config_file cfg;
		if(cfg.open("../etc/path-not-cross.ini"))
			break;

		auto kset=cfg.keys();
		if(kset.empty())
			break;

		for(auto k:kset)
		{
			if(strncmp(k,"pt",2)!=0)
				continue;

			const char* v=cfg.get(k,"");

			point tmp;
			if(sscanf(v,"%lf,%lf",&tmp.x,&tmp.y)==2)
				no_cross.push_back(tmp);
		}

		for(auto p:no_cross)
		{
			log_info("no_cross_point:x=%lf,y=%lf",p.x,p.y);
		}
		break;
	}while(1);

	std::vector<std::vector<int>> p0(ret.size());
	std::vector<base_path> ret2;
	for(int i=0,len=ret.size();i<len;i++)
	{
		p0[i].push_back(ret[i][0]);
		for(int j=i+1;j<len;j++)
		{
			if(i==j) continue;

			point cr=ret[i].cross(v,ret[j]);
			if(cr.empty())
				continue;
			
			if(in_no_cross(cr))
				continue;
			
			double arg=fabs(ret[i].as_line(v).arg()-ret[j].as_line(v).arg());
			while(arg>PI/2) 
				arg=PI-arg;
			
			if(arg/PI*180<5)//相交小于5度,不切分已有路径
				continue;
			
			int id=v.add(cr,arg,v[ret[i][0]].sid0,v[ret[j][0]].sid0);
			p0[i].push_back(id);
			p0[j].push_back(id);
		}
		p0[i].push_back(ret[i][1]);

		std::sort(p0[i].begin(),p0[i].end(),[&v](int i0,int i1){ return v[i0]<v[i1]; });
#if 0
		if(p0[i].size())
		{
			for(int v=0;v<2;v++)
			{
				if(v[ret[i][v]].dist(v[p0[i].front()])<3)
					continue;
				if(v[ret[i][v]].dist(v[p0[i].back()])<3)
					continue;

				p0[i].push_back(ret[i][v]);
				std::sort(p0[i].begin(),p0[i].end(),[&v](int i0,int i1){ return v[i0]<v[i1]; });
			}
		}
		else
		{
			std::sort(p0[i].begin(),p0[i].end(),[&v](int i0,int i1){ return v[i0]<v[i1]; });
		}
#endif

		auto it=std::unique(p0[i].begin(),p0[i].end());
		p0[i].erase(it,p0[i].end());

		for(int j=1,cnt=p0[i].size();j<cnt;j++)
		{
			ret2.push_back(base_path(p0[i][j - 1], p0[i][j]));
			ret2.back().sid = ret[i].sid;
		}
	}

	remove_empty(ret2,v);
	remove_dup(ret2);
	sort_path(ret,v);
	log_path(ret2,v,"拆分后");

	return std::move(ret2);
}

#if 0
struct ghash
{
	static std::tuple<int,int> decode(unsigned h)
	{
		const uint64_t S=0x8000000000000000;

		int x=0,y=0;
		for(int i=0;i<64;i++)
		{
			x<<=1;
			y<<=1;

			if(h&S) 
				x|=1;
			h<<=1;

			if(h&S) 
				y|=1;
			h<<=1;
		}

		return std::make_tuple(x-2147483648,y-2147483648);
	}

	static uint64_t encode(int64_t x, int64_t y)
	{
		return encode_(x+2147483648,y+2147483648);
	}

public: //test
	static void test_code(int64_t x,int64_t y)
	{
		uint64_t h=ghash::encode(x,y);
		auto t=ghash::decode(h);

		printf("src x=%X,y=%X hash=%X,check x=%X,y=%X\n",x,y,h,std::get<0>(t),std::get<1>(t));
	}

	static void test()
	{
		for(int i=0;i<10;i++)
		{
			test_code((4<<i)-1,(4<<i)-1);
			test_code((4<<i)-1,(4<<i));
			test_code((4<<i)-1,(4<<i)-1);
			test_code((4<<i),(4<<i)-1);
		}
	}
private:
	static unsigned encode_(unsigned short x, unsigned short y)
	{
		const unsigned S=0x8000;
		unsigned r=0;
		for(int i=0;i<16;i++)
		{
			r<<=2;
			if(x&S)
			{
				r|=(y&S)?3:2;
			}
			else
			{
				if(y&S) r|=1;
			}

			x<<=1;
			y<<=1;
		}
		
		return r;
	}
};
#endif


struct geolist
{
	std::unordered_map<uint64_t,int> geo2path;
public:

	static uint64_t encode(double x0,double y0)
	{
		uint64_t x=(uint32_t)(x0*10);
		uint64_t y=(uint32_t)(y0*10);

		return (x<<32)|y;
	}

	int find(double x,double y)const
	{
		uint64_t h=encode(x,y);

		auto it=geo2path.find(h);

		if(it==geo2path.end())
			return -1;

		return it->second;
	}

	void add(double x,double y,int id)
	{
		uint64_t h=encode(x,y);
		geo2path.insert(std::make_pair(h,id));
	}

	int size()
	{
		return geo2path.size();
	}

	void print()
	{
		for(auto it=geo2path.begin();it!=geo2path.end();++it)
		{
			//std::cout<<it->first<<"\n";
            printf("%ld\n",it->first);
		}
	}

	geolist()
	{
	}

	~geolist()
	{
	}
};

struct graph
{
	vertex_list v;
	std::vector<std::vector<int>>  d;   //索引为起始顶点,数组内容为目标点
	std::vector<std::array<int,2>> l;	//bast_path list
	geolist geo;

	graph()
	{}

	void init(const vertex_list&v_,const std::vector<base_path>&bp)
	{
		for(auto&p:bp)
		{
			int from=v.add(v_[p[0]]);
			int to=v.add(v_[p[1]]);

			l.push_back({from,to});

			int id=l.size()-1;

			line_v lv(v[from],v[to]);

			log_info("graph::init() site:%d line:%s\n",p.sid, lv.to_string().c_str());

			double cos=lv.cos_k();
			double sin=lv.sin_k();

			double x,y;
			for(double r=0,len=lv.length();r<len+0.1;r+=0.05)
			{
				x=lv[0].x+r*cos;
				y=lv[0].y+r*sin;

//				printf("x=%lf,y=%lf\n",x,y);

				for(int i=-1;i<=1;i++)
				for(int j=-1;j<=1;j++)
				{
					geo.add(x+i/10.,y+j/10.,id);
				}
			}

			add(from,to);
		}
	}

	std::vector<line_v>  find_possible_path(const point&from,double dist) const
	{
		std::vector<line_v> ret;

		int start_pt_id=v.find(from,dist);
		if(start_pt_id==-1)
			return std::move(ret);

		point start_pt=v[start_pt_id];

		for(uint32_t i=0;i<d[start_pt_id].size();i++)
		{
			ret.push_back(line_v(start_pt,v[d[start_pt_id][i]]));
		}

		return std::move(ret);
	}

	void add(int from,int to)
	{
		if((int)d.size()<=from) d.resize(from+1);
		if((int)d.size()<=to) d.resize(to+1);

		d[from].push_back(to);
		d[to].push_back(from);
	}

	bool find(std::vector<int>&ret,int from,std::array<int,2>&to,std::set<int>&ex,int level)
	{
		if(level--<0)
			return false;

		ret.push_back(from);

		for(int p:d[from]) //在当前路径
		{
			if(ex.find(p)!=ex.end()) //找过
				continue;

			if(p==to[0]||p==to[1])//找到
				return true;
//			{
//				ret.push_back(p);
//				return true;
//			}
		}

		ex.insert(from);

		for(int p:d[from])//在下级路径
		{
			if(ex.find(p)!=ex.end())//找过
				continue;
			if(find(ret,p,to,ex,level)) //找到
			{
				return true;
			}
		}

		ret.pop_back();
		return false;
	}

	bool is_at_path(const point&pt)const
	{
		return geo.find(pt.x,pt.y)>=0;
	}

	struct item
	{
		item(int _vid=-1, int _g=0,int _h=0,std::shared_ptr<item> _parent=nullptr)
			:vid(_vid)
			,g(_g)
			,h(_h)
			,parent(_parent)
		{
		}
		int vid=-1,g=0,h=0;
		std::shared_ptr<item> parent;

		int cost()const {return g+h;}

		bool operator< (const item&i) const
		{
			return vid<i.vid;
		}
	};

	std::vector<point> find2(const point&from,const point&to)
	{
		int f=geo.find(from.x,from.y);
		int t=geo.find(to.x,to.y);

		if(f<0 || t<0 || f==t)
			return {};

		std::set<std::shared_ptr<item>> open_set;
		std::set<int> close_set;
		open_set.insert(std::make_shared<item>(l[f][0],from.dist(v[l[f][0]]),to.dist(v[l[f][0]])));
		open_set.insert(std::make_shared<item>(l[f][1],from.dist(v[l[f][1]]),to.dist(v[l[f][1]])));

		std::shared_ptr<item> cur;
		while(open_set.size()>0)
		{
			cur=*open_set.begin();
			for(auto&i:open_set)
			{
				if(i->cost()<cur->cost())
					cur=i;
			}
			open_set.erase(cur);
			close_set.insert(cur->vid);
			if(cur->vid==l[t][0]||cur->vid==l[t][1])
				break;

			for(auto vid:d[cur->vid])
			{
				if(close_set.find(vid)!=close_set.end())
					continue;

				open_set.insert(std::make_shared<item>(vid,cur->g+v[cur->vid].dist(v[vid]),to.dist(v[vid]),cur));
			}
		}

		if(open_set.size()==0)
		{
			return {};
		}

		std::vector<point> rc;
		while(cur.get())
		{
			rc.push_back(v[cur->vid]);
			cur=cur->parent;
		}

		std::reverse(rc.begin(),rc.end());
		rc.push_back(to);
		auto bp=from;
		auto it1=rc.begin();
		for(auto it2=it1+1;it1!=rc.end() && it2!=rc.end();it2++)
		{
			if(line(bp,*it1).dist(*it2)<0.1)
			{
				*it1=*it2;
			}
			else
			{
				bp=*it1++;
				*it1=*it2;
			}
		}

		rc.erase(it1,rc.end());

		if(rc.size() && from.dist(*rc.begin())<0.1)
		{
			rc.erase(rc.begin());
		}

		return std::move(rc);
	}

	std::vector<point> find(const point&from,const point&to)
	{
		int f=geo.find(from.x,from.y);
		int t=geo.find(to.x,to.y);

		if(f<0 || t<0 || f==t)
			return {};
#if 0
		std::vector<point> rc[2];
		for(int i=0;i<2;i++)
		{
			std::vector<int> ret;
			std::set<int> ex({l[f][1-i]});
			if(find(ret,l[f][i],l[t],ex,2))
			{
				for(auto id:ret)
					rc[i].push_back(v[id]);
			}
		}
		if(!rc[0].empty() && (rc[1].empty() || rc[0].size() < rc[1].size()))
			return std::move(rc[0]);
		else if(!rc[1].empty())
			return std::move(rc[1]);
#endif
		std::vector<int> ret;
		int size=v.size();
		std::vector<double> mat(size+1,-1);
		std::vector<double> trace(size+1,-1);
		std::vector<bool> val(size+2,false);
		mat[l[t][0]]=to.dist(v[l[t][0]]);
		mat[l[t][1]]=to.dist(v[l[t][1]]);
		int f0=l[f][0],f1=l[f][1];
		for(int i=0;i<2;i++)
		{
			if(mat[f0]!=-1 && mat[f1]!=-1)
				break;
			for(int j=0;j<size;j++)
				if(mat[j]!=-1)val[j]=true;
			for(int j=0;j<size;j++)
			{
				if(val[j]==false)continue;
				for(unsigned int k=0;k<d[j].size();k++)
				{
					double dist=v[j].dist(v[d[j][k]]);
					if(mat[d[j][k]]==-1 || mat[j]+dist < mat[d[j][k]])
					{
						mat[d[j][k]] = mat[j]+dist;
						trace[d[j][k]] = j;
					}
				}
			}
		}
		mat[f0]=mat[f0]+from.dist(v[l[f][0]]);
		mat[f1]=mat[f1]+from.dist(v[l[f][1]]);
		std::vector<point> rc;
		if(mat[f0]!=-1 && (mat[f1]==-1 || mat[f0] < mat[f1]))
		{
			int temp=f0;
			while(temp!=-1)
			{
				rc.push_back(v[temp]);
				temp=trace[temp];
			}
			return std::move(rc);
		}
		else if(mat[f1]!=-1)
		{
			int temp=f1;
			while(temp!=-1)
			{
				rc.push_back(v[temp]);
				temp=trace[temp];
			}
			return std::move(rc);
		}
		return {};
	}
};

safe_shared_ptr<graph> g_graph(std::make_shared<graph>());
}//namespace

void card_path::init()
{
	std::shared_ptr<graph> local_graph=std::make_shared<graph>();

	handle_path hp;
	sit_list::instance()->accept(hp);
	std::vector<base_path> opath=init_path(hp.ret,hp.v);
	local_graph->init(hp.v,opath);

	g_graph.set(local_graph);
}

card_path&card_path::inst()
{
	static card_path path;
	return path;
}

std::vector<point> card_path::find_path(const point&from,const point&to)const
{
	return g_graph.get()->find2(from,to);
}

bool card_path::is_at_path(const point&pt)const
{
	return g_graph.get()->is_at_path(pt);
}

std::vector<line_v>  card_path::find_possible_path(const point&from,double dist) const
{
	return std::move(g_graph.get()->find_possible_path(from,dist));
}

#ifdef __DEBUG__

void test_at_path(card_path&cp,const point&pt)
{
	if(cp.is_at_path(pt))
		log_info("test (%.3lf,%.3lf) is-at-path:true\n",pt.x,pt.y);
	else
		log_info("test (%.3lf,%.3lf) is-at-path:false\n",pt.x,pt.y);
}

void test_find_path(card_path&cp,const point&p1,const point&p2)
{
	printf("\nfind-path:  from=(%.3lf,%.3lf),to=(%.3lf,%.3lf)\n",p1.x,p1.y,p2.x,p2.y);
	std::vector<point> rc=cp.find_path(p1,p2);
	for(uint32_t i=0;i<rc.size();i++)
		log_info("x=%.3lf,y=%.3lf\n",rc[i].x,rc[i].y);
}

void test_find_poss_path(const card_path&cp ,const point&from)
{
	log_info("\nfind-poss_path:  from=(%.3lf,%.3lf)\n",from.x,from.y);
	std::vector<line_v> rc=cp.find_possible_path(from,3);
	for(uint32_t i=0;i<rc.size();i++)
	{
		log_info("poss path from=(%.3lf,%.3lf) to=(%.3lf,%.3lf)\n", rc[i][0].x,rc[i][0].y, rc[i][1].x,rc[i][1].y);
	}
}

int main()
{
//	std::unique_ptr<sit_list> sites(new sit_list());
	//sit_list::instance()->load("data_reader_antenna.txt","path_tof.txt");
	sit_list::instance()->load("1.txt","2.txt");

	card_path cp;

	cp.init();
#if 0
	{
		test_at_path(cp,point(4773.104654,-104.0887));

		test_at_path(cp,point(4727,-74.8));
		test_at_path(cp,point(4727,-75.0));
		test_at_path(cp,point(4727,-75.2));
		test_at_path(cp,point(4727,-75.8));
		test_at_path(cp,point(4727,-90));
		test_at_path(cp,point(4727,-89.6));
		test_at_path(cp,point(4727,-89.8));
		test_at_path(cp,point(4727,-90));
		test_at_path(cp,point(4727,-90.2));
		test_at_path(cp,point(4727,-90.4));
	}
#endif
	//test_at_path(cp,point(4726.90,376.85));
	test_find_path(cp,point(-227.6,174.9),point(-201.3,175.5));
	test_find_path(cp,point(-227.625219,174.945670),point(-170.085722,176.101574));
	test_find_path(cp,point(-393.1944,262.5324),point(-366.0754,274.1253));
	//test_find_path(cp,point(4637.000000,-75),point(4727,135));
#if 1
	{
		test_find_path(cp,point(4637.000000,-75),point(4727,135));
		test_find_path(cp,point(4637.000000,-75),point(4727,120));
		test_find_path(cp,point(4700,-75),point(4727,120));
		test_find_path(cp,point(4725,-75),point(4727,135));
		test_find_path(cp,point(4727,-89.7),point(6144.3,-523));
	}
#endif
#if 0
	{
		test_find_poss_path(cp, point(4727,-89));
		test_find_poss_path(cp, point(4727,-90));

		test_find_poss_path(cp, point(4724,-75));
		test_find_poss_path(cp, point(4725,-75));
		test_find_poss_path(cp, point(4726,-75));
		test_find_poss_path(cp, point(4727,-75));
		test_find_poss_path(cp, point(4728,-75));
		test_find_poss_path(cp, point(4727,-7));

		test_find_poss_path(cp, point(4726.6,33));
	}
#endif
	return 0;
}
#endif