抓取多边形
可以把long替换成double,按需
想要更更更更更精确,可以自己弄象限和叉积判断Part
Reference:
https://www.geometrictools.com/Documentation/MinimalCycleBasis.pdf
如果要轮廓线,可以去掉所有边有两条的,如果再要去掉内部多边形,可以判断点是否在多边形内
using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
namespace polygoncircles
{
public struct nd
{
public nd(long x, long y, int v, int oldv, double lng = 0, double lat = 0)
{
this.x = x;
this.y = y;
this.v = v;
this.oldv = oldv;
this.lng = lng;
this.lat = lat;
}
public long x;
public long y;
public int v;
public int oldv;
public double lng;
public double lat;
}
//public class Mercator
//{
// public static nd toxy(nd nd)
// {
// var latitude = nd.y; // (φ)
// var longitude = nd.x; // (λ)
// var mapWidth = 2000000;
// var mapHeight = 1000000;
// // get x value
// long x = (longitude + 180) * (mapWidth / 360);
// // convert from degrees to radians
// long latRad = (long)(latitude * Math.PI / 180);
// // get y value
// var mercN = Math.Log(Math.Tan((Math.PI / 4) + (latRad / 2)));
// var y = (long)((mapHeight / 2) - (mapWidth * mercN / (2 * Math.PI)));
// return new nd(x, y, nd.v, nd.oldv, nd.lng, nd.lat);
// }
//}
public class Part : IEquatable<Part>
{
public nd a;
public nd b;
public double? _val;
public double val
{
get
{
if (_val==null)
_val=val1();
return _val.Value;
}
}
public double val1()
{
nd aa = a;
aa.x = a.x + 10000000;
var p1 = (Math.Atan2(b.y - a.y, b.x - a.x) * 180 / Math.PI + 450) % 360;
var p2 = (Math.Atan2(aa.y - a.y, aa.x - a.x) * 180 / Math.PI + 450) % 360;
var val = p1 - p2;
return val;
}
public override int GetHashCode()
{
return b.v;
}
public bool Equals(Part other)
{
if (other == null) return false;
return (this.b.v.Equals(other.b.v));
}
}
public class Cal
{
long N = 1;
//public void init(long n)
//{
// //N = (n + 1) * 2;
// //vert = new List<List<Part>>();
//}
public Cal()
{
}
public void setinput(List<Tuple<int, int>> inputs, List<nd> vt)
{
vt = vt.OrderBy(p => p.x).ThenByDescending(p => p.y).ToList();
Dictionary<int, nd> tos = new Dictionary<int, nd>();
int cnt = 0;
points = new List<nd>() { vt[0] };
var nt = vt[0];
tos.Add(vt[0].v, nt);
for (int i = 1; i < vt.Count; i++)
{
if (vt[i].x == vt[i - 1].x && vt[i].y == vt[i - 1].y)
{
tos.Add(vt[i].v, nt);
}
else
{
nt = vt[i];
points.Add(nt);
tos.Add(vt[i].v, nt);
}
}
//for(int i = 0; i < inputs.Count; i++)
//{
// inputs[i] = new Tuple<int,int>(tos[inputs[i].Item1].v, tos[inputs[i].Item2].v);
//}
//points = vt;
//n = points.Count;
//init(n);
vert = new Dictionary<int, List<Part>>();
for (int i = 0; i < points.Count; i++)
{
vert.Add(points[i].v, new List<Part>());
}
result = new List<List<nd>>();
vis = new Dictionary<int, bool>();
for (int i = 0; i < points.Count; i++)
{
vis.Add(points[i].v, false);
}
System.Diagnostics.Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < inputs.Count; i++)
{
var input = inputs[i];
var x = tos[input.Item1];
var y = tos[input.Item2];
if (x.v == y.v)
continue;
if (!vert.ContainsKey(x.v))
{
vert.Add(x.v, new List<Part>());
}
if (!vert.ContainsKey(y.v))
{
vert.Add(y.v, new List<Part>());
}
if (vert[x.v].Any(p => p.b.v == y.v))
continue;
if (vert[y.v].Any(p => p.b.v == x.v))
continue;
vert[x.v].Add(new Part()
{
a = x,
b = y
});
vert[y.v].Add(new Part()
{
a = y,
b = x
});
}
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
for (int i = 0; i < points.Count; i++)
{
vert[points[i].v] = vert[points[i].v].OrderBy(p => p.val).ToList();
//vert[points[i].v].Sort();
}
}
public void setsubs(List<nd> vt, ref Dictionary<int, List<Part>> verts)
{
points = vt;
//n = points.Count;
//init(n);
result = new List<List<nd>>();
vis = new Dictionary<int, bool>();
for (int i = 0; i < points.Count; i++)
{
vis.Add(points[i].v, false);
}
this.vert = verts;
for (int i = 0; i < points.Count; i++)
{
//vert[points[i].v].Sort();
vert[points[i].v] = vert[points[i].v].OrderBy(p => p.val).ToList();
}
}
long n;
Dictionary<int, bool> vis;
List<nd> points;
List<List<nd>> result;
List<nd> subs;
Dictionary<int, List<Part>> vert;
public int getIndex(ref List<Part> list, int v)
{
for (int i = 0; i < list.Count; i++)
{
if (list[i].b.v == v)
return i;
}
return -1;
}
public void sub4(int q, int u, int v, ref List<nd> list)
{
var op = list.FirstOrDefault(p => p.v == u);
//var ind = list.Select(p => p.v).ToList().IndexOf(u);
nd cp = new nd(op.x, op.y, vert.Count, op.v, op.lng, op.lat);
var oplist = vert[u].ToList();
var cplist = new List<Part>();
//var culist = oplist.ToList();
var lindex = getIndex(ref oplist, q);
var rindex = getIndex(ref oplist, v);
//var lindex = oplist.Select(p => p.b.v).ToList().IndexOf(q);
//var rindex = oplist.Select(p => p.b.v).ToList().IndexOf(v);
if (lindex < rindex)
lindex = lindex + vert[u].Count;
if (lindex > rindex + 1)
{
for (int i = rindex + 1; i < lindex; i++)
{
int ii = i % vert[u].Count;
var mv = vert[u][ii];
var index = oplist.Select(p => p.b.v).ToList().IndexOf(mv.b.v);
oplist.RemoveAt(index);
index = vert[mv.b.v].Select(p => p.b.v).ToList().IndexOf(u);
vert[mv.b.v].RemoveAt(index);
cplist.Add(new Part() { a = cp, b = mv.b });
vert[mv.b.v].Add(new Part() { a = mv.b, b = cp });
//vert[mv.b.v].Sort();
}
//cplist.Sort();
vert[u] = oplist;
vert.Add(vert.Count, cplist);
points.Add(cp);
//if (vis[cp.v])
// return;
var ret = resub(cp);
result.AddRange(ret);
}
}
public void sub3(nd u, nd v, ref List<nd> list)
{
nd cp = new nd(u.x, u.y, vert.Count, u.v, u.lng, u.lat);
//var oplist = vert[u.v].ToList();
var cplist = new List<Part>();
var mv = v;
//var index = getIndex(ref vert[u.v], mv.v);
var index = vert[u.v].Select(p => p.b.v).ToList().IndexOf(mv.v);
vert[u.v].RemoveAt(index);
//index = getIndex(ref vert[mv.v], u.v);
index = vert[mv.v].Select(p => p.b.v).ToList().IndexOf(u.v);
vert[mv.v].RemoveAt(index);
cplist.Add(new Part() { a = cp, b = mv });
vert[mv.v].Add(new Part() { a = mv, b = cp });
vert.Add(vert.Count, cplist);
points.Add(cp);
var ret = resub(cp);
result.AddRange(ret);
}
public void tra(nd u, ref List<nd> subs)
{
Stack<nd> s = new Stack<nd>();
s.Push(u);
while (s.Count>0)
{
u = s.Pop();
if (vis[u.v])
{
continue;
}
subs.Add(u);
vis[u.v] = true;
for (int i = 0; i < vert[u.v].Count; i++)
{
nd v = vert[u.v][i].b;
s.Push(v);
}
}
}
public List<List<nd>> resub(nd u)
{
subs = new List<nd>();
vis = new Dictionary<int, bool>();
for (int i = 0; i < points.Count; i++)
{
vis.Add(points[i].v, false);
}
tra(u, ref subs);
subs = subs.OrderBy(p => p.x).ThenByDescending(p => p.y).ToList();
var pps = new List<nd>();
int j = 0;
for(int i = 0; i < points.Count; i++)
{
var nt = points[i];
while (j<subs.Count&&subs[j].v < nt.v)
{
j++;
}
if(subs[j].v!=nt.v)
pps.Add(nt);
}
points = pps;
Cal cal = new Cal();
cal.setsubs(subs, ref vert);
return cal.all();
}
public void found(nd ud,ref List<nd> list)
{
Dictionary<int, int> circles = new Dictionary<int, int>();
var cpoints = new List<int>() { 0 };
for (int i = 1; i < list.Count - 1; i++)
{
var uu = list[i];
if (circles.ContainsKey(uu.v))
{
var skip = circles[uu.v];
if (!cpoints.Any(p => p == skip))
cpoints.Add(skip);
for (int j = skip + 1; j < i; j++)
{
if (circles.ContainsKey(list[j].v))
{
circles.Remove(list[j].v);
}
cpoints.Remove(j);
}
list.RemoveRange(skip, i - skip);
i = i - (i - skip);
}
else
{
circles.Add(uu.v, i);
}
}
if (list.Count > 3)
{
for (int i = 0; i < cpoints.Count; i++)
{
if (i == 0)
{
sub4(list[list.Count - 2].v, list[cpoints[i]].v, list[cpoints[i] + 1].v, ref list);
}
else
{
sub4(list[cpoints[i] - 1].v, list[cpoints[i]].v, list[cpoints[i] + 1].v, ref list);
}
}
}
else
{
sub3(list[0], list[1], ref list);
}
if (list.Count > 3)
{
//if (isok(list))
{
result.Add(list);
}
}
List<int> cnts = list.Select(p => vert[p.v].Count).ToList();
for (int k = 0; k < list.Count - 1; k++)
{
var jv = list[k];
if (cnts[k] <= 2)
{
for (int j = 0; j < vert[jv.v].Count; j++)
{
var tv = vert[jv.v][j].b;
rm(tv, jv);
}
}
else
{
break;
}
}
rm(list[0], list[1]);
}
public void find(nd pd, nd ud, ref List<nd> list)
{
list.Add(ud);
while (list[0].v != ud.v)
{
int p = pd.v;
int u = ud.v;
//Console.WriteLine(ud.v);
var index = vert[u].Select(q => q.b.v).ToList().IndexOf(p);
var v = vert[u][(index - 1 + vert[u].Count) % vert[u].Count].b;
list.Add(v);
pd = ud;
ud = v;
}
found(ud, ref list);
}
public class CompareList : IEqualityComparer<List<nd>>
{
public bool Equals([AllowNull] List<nd> x, [AllowNull] List<nd> y)
{
var xx = x.Select(p => p.oldv).Distinct().OrderBy(p => p).ToList();
var yy = y.Select(p => p.oldv).Distinct().OrderBy(p => p).ToList();
return xx.SequenceEqual(yy);
}
public int GetHashCode([DisallowNull] List<nd> obj)
{
long hash = 19;
var list = obj.Select(p => p.oldv).Distinct().OrderBy(p => p).ToList();
foreach (var foo in list)
{
hash = (hash * 31 + foo) % 100000007;
}
return (int)hash;
}
}
public void rm(nd x, nd y)
{
int rindex = vert[x.v].Select(p => p.b.v).ToList().IndexOf(y.v);
if (rindex != -1)
vert[x.v].RemoveAt(rindex);
rindex = vert[y.v].Select(p => p.b.v).ToList().IndexOf(x.v);
if (rindex != -1)
vert[y.v].RemoveAt(rindex);
}
public void rrm(nd u, nd v)
{
rm(u, v);
if (vert[v.v].Count == 1)
{
//points.Remove(v);
rrm(v, vert[v.v][0].b);
}
}
List<nd> list = new List<nd>();
static long tt = 0;
public void rrrm()
{
//System.Diagnostics.Stopwatch stopwatch = new Stopwatch();
//stopwatch.Start();
foreach (var u in points)
{
if (vert[u.v].Count == 1)
{
rrm(u, vert[u.v][0].b);
}
}
//stopwatch.Stop();
//tt += stopwatch.ElapsedMilliseconds;
//Console.WriteLine(tt);
}
public void rrrm(ref List<nd> pps)
{
//System.Diagnostics.Stopwatch stopwatch = new Stopwatch();
//stopwatch.Start();
foreach (var u in pps)
{
if (vert[u.v].Count == 1)
{
rrm(u, vert[u.v][0].b);
}
}
//stopwatch.Stop();
//tt += stopwatch.ElapsedMilliseconds;
//Console.WriteLine(tt);
}
public List<List<nd>> all()
{
//points = points.OrderBy(p => p.x).ThenByDescending(p => p.y).ToList();
var pps = points.ToList();
rrrm();
for (int i = 0; i < pps.Count; i++)
{
var u = pps[i];
while (vert[u.v].Count > 0)
{
//if (vert[u.v].Count > 0)
{
var v = vert[u.v][0].b;
//Console.WriteLine();
//Console.WriteLine(u.v);
list = new List<nd>() { u };
find(u, v, ref list);
rrrm(ref list);
//Console.WriteLine();
}
}
}
//result = result.Distinct(new CompareList()).ToList();
return result;
}
const double eps = 1e-8;
long dcmp(long x)
{
if (x < -eps) return -1;
else return (x > eps) ? 1 : 0;
}
long dot(nd p0, nd p1, nd p2)
{
return (p1.x - p0.x) * (p2.x - p0.x) + (p1.y - p0.y) * (p2.y - p0.y);
}
long cross(nd p0, nd p1, nd p2)
{
return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}
//public void check(List<nd> path, int u, ref List<int> clist)
//{
// if (!vis.ContainsKey(u))
// {
// vis[u] = false;
// }
// if (vis[u] || clist.Distinct().Count() >= 2 || path.Any(p => p.oldv == u))
// {
// return;
// }
// vis[u] = true;
// for (int i = 0; i < vert[u].Count; i++)
// {
// int oldv = vert[u][i].b.oldv;
// bool at = path.Any(p => p.oldv == oldv);
// if (!at)
// {
// check(path, oldv, ref clist);
// }
// else
// {
// clist.Add(oldv);
// }
// }
//}
public bool isok(List<nd> olist)
{
var path = olist;
path = path.ToList().Skip(1).ToList();
bool f = false;
for (int i = 0; i < olist.Count; i++)
{
var ii = olist[i].v;
for (int j = 0; j < vert[ii].Count; j++)
{
int p1 = vert[ii][j].a.v;
int p2 = vert[ii][j].b.v;
if (p1 == p2)
continue;
if (pinp(vert[ii][j].b, olist) == 1)
{
Console.WriteLine(string.Join(" ",olist.Select(p=>p.oldv)));
Console.WriteLine();
f = true;
return !f;
}
//var at = path.Any(p => p.v == p1) && path.Any(p => p.v == p2);
//var index1 = path.Select(p => p.v).ToList().IndexOf(p1);
//var index2 = path.Select(p => p.v).ToList().IndexOf(p2);
//if (at && ((index1 + 1) % path.Count != index2) && ((index2 + 1) % path.Count != index1))
//{
// f = true;
// return !f;
//}
}
}
//for (int j = 0; j < points.Count; j++) //加不加看是否介意不是环的点和边
//{
// if (pinp(points[j], result[i]) == 1)
// {
// f = true;
// break;
// }
//}
return !f;
}
//public bool isok(List<nd> olist)
//{
// var path = olist;
// path = path.ToList().Skip(1).ToList();
// bool f = false;
// for (int j = 0; j < points.Count; j++)
// {
// vis = new Dictionary<int, bool>();
// for (int i = 0; i < points.Count; i++)
// {
// vis.Add(points[i].v, false);
// }
// List<int> clist = new List<int>();
// if (pinp(points[j], olist) == 1 && !olist.Any(p => p.v == points[j].v))
// {
// check(path, points[j].oldv, ref clist);
// if (clist.Distinct().Count() >= 2)
// {
// f = true;
// break;
// }
// }
// }
// for (int i = 0; i < points.Count; i++)
// {
// for (int j = 0; j < vert[i].Count; j++)
// {
// int p1 = vert[i][j].a.v;
// int p2 = vert[i][j].b.v;
// var at = path.Any(p => p.oldv == p1) && path.Any(p => p.oldv == p2);
// var index1 = path.Select(p => p.oldv).ToList().IndexOf(p1);
// var index2 = path.Select(p => p.oldv).ToList().IndexOf(p2);
// if (at && ((index1 + 1) % path.Count != index2) && ((index2 + 1) % path.Count != index1))
// {
// f = true;
// }
// }
// }
// //for (int j = 0; j < points.Count; j++) //加不加看是否介意不是环的点和边
// //{
// // if (pinp(points[j], result[i]) == 1)
// // {
// // f = true;
// // break;
// // }
// //}
// return !f;
//}
//public List<List<nd>> nopoints(List<List<nd>> result)
//{
// var ret = new List<List<nd>>();
// for (int i = 0; i < result.Count; i++)
// {
// var f = isok(result[i]);
// if (f)
// ret.Add(result[i]);
// }
// return ret;
//}
long pinl(nd p0, nd p1, nd p2)
{
return dcmp(cross(p0, p1, p2)) == 0 && dcmp(dot(p0, p1, p2)) <= 0 ? 1 : 0;
}
long pinp(nd cp, List<nd> p)
{
long len = p.Count - 1;
int i;
long k, d1, d2, wn = 0;
for (i = 0; i < len; i++)
{
if (pinl(cp, p[i], p[i + 1]) == 1) return 2;
k = dcmp(cross(p[i], p[i + 1], cp));
d1 = dcmp(p[i + 0].y - cp.y);
d2 = dcmp(p[i + 1].y - cp.y);
if (k > 0 && d1 <= 0 && d2 > 0) wn++;
if (k < 0 && d2 <= 0 && d1 > 0) wn--;
}
return wn != 0 ? 1 : 0;
}
}
class Program
{
static void Main(string[] args)
{
//var pn = Console.ReadLine();
//List<nd> vt = new List<nd>()
//{
//};
//for (int i = 0; i < int.Parse(pn); i++)
//{
// var input = Console.ReadLine();
// var x = int.Parse(input.Split(' ')[0]);
// var y = int.Parse(input.Split(' ')[input.Split(' ').Length - 1]);
// vt.Add(new nd(x, y, i, i,x,y));
//}
//Console.ReadLine();
//var pe = Console.ReadLine();
//List<Tuple<int, int>> inputs = new List<Tuple<int, int>>();
//for (int i = 0; i < int.Parse(pe); i++)
//{
// var input = Console.ReadLine();
// int x = int.Parse(input.Split(' ')[0]);
// int y = int.Parse(input.Split(' ')[input.Split(' ').Length - 1]);
// inputs.Add(new Tuple<int, int>(x, y));
//}
List<nd> vt = new List<nd>() {
new nd(2,0,0,0),
new nd(2,2,1,1),
new nd(1,0,2,2),
new nd(1,1,3,3),
new nd(1,2,4,4),
new nd(0,0,5,5),
new nd(0,2,6,6)};
List<Tuple<int, int>> inputs = new List<Tuple<int, int>>() {
new Tuple<int,int>(0,1),
new Tuple<int,int>(0,2),
new Tuple<int,int>(1,4),
new Tuple<int,int>(2,3),
new Tuple<int,int>(3,4),
new Tuple<int,int>(2,5),
new Tuple<int,int>(4,6),
new Tuple<int,int>(5,6)};
//List<nd> vt = new List<nd>() {
//new nd(0,4,0,0),
//new nd(4,4,1,1),
//new nd(4,0,2,2),
//new nd(0,0,3,3),
//new nd(1,1,4,4),
//new nd(3,1,5,5),
//new nd(2,3,6,6)};
//List<Tuple<int, int>> inputs = new List<Tuple<int, int>>() {
//new Tuple<int,int>(0,1),
//new Tuple<int,int>(1,2),
//new Tuple<int,int>(2,3),
//new Tuple<int,int>(3,0),
//new Tuple<int,int>(3,4),
//new Tuple<int,int>(4,5),
//new Tuple<int,int>(4,6),
//new Tuple<int,int>(5,6)};
//List<nd> vt = new List<nd>() {
//new nd(-2,3,0,0),
//new nd(-1,3,1,1),
//new nd(-3,2,2,2),
//new nd(-2,2,3,3),
//new nd(-1,2,4,4),
//new nd(0,2,5,5),
//new nd(-3,1,6,6),
//new nd(-2,1,7,7),
//new nd(-1,1,8,8),
//new nd(0,1,9,9),
//new nd(-2,0,10,10),
//new nd(-1,0,11,11),
//new nd(-2,-1,12,12)};
//List<Tuple<int, int>> inputs = new List<Tuple<int, int>>() {
//new Tuple<int,int>(0,1),
//new Tuple<int,int>(0,3),
//new Tuple<int,int>(2,3),
//new Tuple<int,int>(3,4),
//new Tuple<int,int>(1,4),
//new Tuple<int,int>(4,5),
//new Tuple<int,int>(2,6),
//new Tuple<int,int>(3,7),
//new Tuple<int,int>(4,8),
//new Tuple<int,int>(5,9),
//new Tuple<int,int>(6,7),
//new Tuple<int,int>(7,8),
//new Tuple<int,int>(8,9),
//new Tuple<int,int>(7,10),
//new Tuple<int,int>(8,11),
//new Tuple<int,int>(10,11),
//new Tuple<int,int>(1,3),
//new Tuple<int,int>(10,12)};
//List<nd> vt = new List<nd>() {
//new nd(1,2,0,0),
//new nd(2,3,1,1),
//new nd(3,4,2,2),
//new nd(4,5,3,3),
//new nd(5,6,4,4),
//new nd(6,1,5,5),
//new nd(6,4,6,6),
//new nd(7,8,7,7),
//new nd(8,9,8,8),
//new nd(9,10,9,9)};
//List<Tuple<int, int>> inputs = new List<Tuple<int, int>>() {
//new Tuple<int,int>(0,1),
//new Tuple<int,int>(1,2),
//new Tuple<int,int>(2,3),
//new Tuple<int,int>(3,4),
//new Tuple<int,int>(4,5),
//new Tuple<int,int>(5,0),
//new Tuple<int,int>(5,3),
//new Tuple<int,int>(6,7),
//new Tuple<int,int>(7,8),
//new Tuple<int,int>(8,9),
//new Tuple<int,int>(9,6)};
//List<nd> vt = new List<nd>() {
//new nd(1,0,0,0),
//new nd(1,1,1,1),
//new nd(0,1,2,2),
//new nd(0,0,3,3)};
//List<Tuple<int, int>> inputs = new List<Tuple<int, int>>() {
//new Tuple<int,int>(0,1),
//new Tuple<int,int>(1,2),
//new Tuple<int,int>(2,3),
//new Tuple<int,int>(3,0)};
Console.WriteLine();
Cal cal = new Cal();
cal.setinput(inputs, vt);
var result = cal.all();
//var ret = cal.nopoints(result);
for (int i = 0; i < result.Count; i++)
{
var path = result[i];
for (int j = 0; j < path.Count; j++)
{
Console.Write(path[j].oldv + " ");
}
Console.WriteLine();
}
}
}
}