Sono nuovo di C# e sta avendo difficoltà a calcolare lo scafo convesso. C# ha una sorta di libreria matematica per questo? Altrimenti, suppongo che dovrò solo implementare il mio.Libreria scafo convesso
risposta
MIConvexHull - https://designengrlab.github.io/MIConvexHull/ - è un'implementazione dello scafo convesso ad alte prestazioni in C#, che supporta anche scafi convessi di dimensioni superiori. Licenza LGPL.
Ecco un algoritmo di scafo convesso 2D che ho scritto utilizzando l'algoritmo Monotone Chain, a.k.a Algoritmo di Andrew.
public static IListSource<Point> ComputeConvexHull(List<Point> points, bool sortInPlace = false)
{
if (!sortInPlace)
points = new List<Point>(points);
points.Sort((a, b) =>
a.X == b.X ? a.Y.CompareTo(b.Y) : a.X.CompareTo(b.X));
// Importantly, DList provides O(1) insertion at beginning and end
DList<Point> hull = new DList<Point>();
int L = 0, U = 0; // size of lower and upper hulls
// Builds a hull such that the output polygon starts at the leftmost point.
for (int i = points.Count - 1; i >= 0 ; i--)
{
Point p = points[i], p1;
// build lower hull (at end of output list)
while (L >= 2 && (p1 = hull.Last).Sub(hull[hull.Count-2]).Cross(p.Sub(p1)) >= 0) {
hull.RemoveAt(hull.Count-1);
L--;
}
hull.PushLast(p);
L++;
// build upper hull (at beginning of output list)
while (U >= 2 && (p1 = hull.First).Sub(hull[1]).Cross(p.Sub(p1)) <= 0)
{
hull.RemoveAt(0);
U--;
}
if (U != 0) // when U=0, share the point added above
hull.PushFirst(p);
U++;
Debug.Assert(U + L == hull.Count + 1);
}
hull.RemoveAt(hull.Count - 1);
return hull;
}
Essa si basa su alcune cose che si suppone che esistano, vedi il mio blog post per i dettagli.
Di seguito è una traslitterazione a C# della stessa sorgente Java utilizzata nella risposta di Qwertie ma senza una dipendenza da classi non standard oltre una classe Point con campi doppi.
class ConvexHull
{
public static double cross(Point O, Point A, Point B)
{
return (A.X - O.X) * (B.Y - O.Y) - (A.Y - O.Y) * (B.X - O.X);
}
public static List<Point> GetConvexHull(List<Point> points)
{
if (points == null)
return null;
if (points.Count() <= 1)
return points;
int n = points.Count(), k = 0;
List<Point> H = new List<Point>(new Point[2 * n]);
points.Sort((a, b) =>
a.X == b.X ? a.Y.CompareTo(b.Y) : a.X.CompareTo(b.X));
// Build lower hull
for (int i = 0; i < n; ++i)
{
while (k >= 2 && cross(H[k - 2], H[k - 1], points[i]) <= 0)
k--;
H[k++] = points[i];
}
// Build upper hull
for (int i = n - 2, t = k + 1; i >= 0; i--)
{
while (k >= t && cross(H[k - 2], H[k - 1], points[i]) <= 0)
k--;
H[k++] = points[i];
}
return H.Take(k - 1).ToList();
}
}
Ho confrontato molti algoritmi/implementazioni di Scafo convesso con tutto il codice fornito. Tutto è incluso in un articolo CodeProject.
Algoritmo rispetto:
- catena Monotono
- MiConvexHull (triangolazioni di Delaunay e Voronoi maglie)
- Graham scansione
- Chan
- Ouellet (la mia)
articoli:
- 2017/10/13 - Banco di prova con algoritmo può/implementazioni: Fast and improved 2D Convex Hull algorithm and its implementation in O(n log h)
- 2014/05/20 - Spiegare il mio algoritmo: A Convex Hull Algorithm and its implementation in O(n log h)
@ephraim, grazie mille per avermelo segnalato. Al momento sto guardando quel caso! –
@ephraim, dove hai avuto il bug, in quale articolo? Non riesco a riprodurlo con il codice del mio ultimo articolo? Hai un suggerimento su come posso vedere il bug da solo? 1 000 000 test con 4 punti (che dovrebbe risultare in 1 punto per quadrante una volta ogni tanto) con tutti gli agloritmi di Ouellet e nessun errore/eccezione? –
@ephraim, Trovato bug! Grazie mille! Era solo nel primo articolo. l'articolo con la correzione dovrebbe essere disponibile molto presto (sarà in cantiere tra 15 minuti e sarà disponibile se approvato da CodeProject ~ probabilmente oggi) –
Molto primo successo in google per 'C# convesso '- http://www.codeproject.com/Articles/29275/Convex-Hull. Hai fatto qualche ricerca? –
sì, l'ho visto. La mia domanda era se C# ha una libreria già esistente per questo ... – Owen