static void Main(string[] args) { var cfs = new CompositeFactors(); var cfHashes = new C5.HashSet <int>(); var b = ImmutableSortedDictionary.CreateBuilder <int, int>(); b.Add(0, Limit); CompositeFactor initial = new CompositeFactor(b); cfs.Add(initial); cfHashes.Add(initial.GetHashCode()); for (int i = 0; i < Limit - 1; i++) { if (i % 100 == 0) { Console.Write($"{(double)i / Limit:P1}, count = {cfs.Count} / {cfs.HashCount}\r"); } var firstUnexpanded = cfs.DeleteMin(); var expansions = firstUnexpanded.Expand(); foreach (var e in expansions) { cfs.Add(e); } cfs.Add(new CompositeFactor(firstUnexpanded.Factors.ToBuilder().Increase(0))); } Console.Out.WriteLine($"\nFound {Limit}th factor"); var answerFactor = cfs.DeleteMin(); mpz_t result = answerFactor.Factors.Aggregate(new mpz_t(1), (res, f) => res * new mpz_t(Primes.Values[f.Key]).Power(f.Value)).Mod(123454321); Console.WriteLine(result); }
/// <summary> /// Adds triangle. If his Vectors should align with another triangles vectors, they need to be the same instances /// </summary> /// <param name="trngls"></param> public void AddTriangleByReference(Triangle trngls) { C5.HashSet <Triangle> incidence = new C5.HashSet <Triangle>(); triangleIncidence.Add(trngls, new ArrayList <Triangle>()); //register each vertex foreach (Vector3 vertex in trngls.vertices) { if (!vertex2Triangle.ContainsKey(vertex)) { vertex2Triangle[vertex] = new ArrayList <Triangle>(); } else { foreach (Triangle triangle in vertex2Triangle[vertex]) { if (incidence.Contains(triangle)) //already found a common vertex { triangleIncidence[triangle].Add(trngls); triangleIncidence[trngls].Add(triangle); } else { incidence.Add(triangle); //first common vertex found -> remember it } } } vertex2Triangle[vertex].Add(trngls); } }
public void UnseqequalityComparerViaBuilder2() { SCG.IEqualityComparer <C5.HashSet <int> > h = C5.EqualityComparer <C5.HashSet <int> > .Default; C5.HashSet <int> s = new C5.HashSet <int>(); s.Add(1); s.Add(2); s.Add(3); Assert.AreEqual(CHC.unsequencedhashcode(1, 2, 3), h.GetHashCode(s)); }
public void HandleEventPoints(C5.HashSet <EventPoint> eventPoints) { if (eventPoints.Count == 0) { return; } var array = eventPoints.ToArray(); MoveSweepLineTo(array[0]); if (eventPoints.Count > 1) // Jeśli w zestawie jest więcej niż jeden element, muszą się one ze sobą przecinać { for (var i = 0; i < array.Length - 1; i++) { for (var j = i + 1; j < array.Length; j++) { CheckIntersection(array[i], array[j]); } } } foreach (var ep in eventPoints) { HandleEventPoint(ep); } }
public C5.HashSet <EventPoint> DeleteMin() // Pobierz i zwróć najmniejszy element kolejki { if (isEmpty()) { throw new Exception("Kolejka jest pusta"); } var entry = _events.DeleteMin(); var hs = new C5.HashSet <EventPoint>(); hs.AddAll(entry.Value); return(hs); }
private void CheckIntersection(EventPoint ep1, EventPoint ep2) // Sprawdza czy istnieje przecięcie pomiędzy dwoma zdarzeniami { if (CurrentSweepPoint == null) { return; } var currentSweepPoint = (PointFr)CurrentSweepPoint; if (ep1 == null || ep2 == null || ep1.Type == EventPointType.Intersection || ep2.Type == EventPointType.Intersection) // Zatrzymaj jeżeli conajmniej jedno ze zdarzeń jest puste lub jest przecięciem { return; } if (ep2.Segment == null || ep1.Segment == null) { throw new ArgumentException("Wartość ep1.Segment i ep2.Segment nie może być pusta"); } var pNullable = ((LineSegmentFr)ep1.Segment).Intersection((LineSegmentFr)ep2.Segment); // Znajdź punkt przecięcia pomiędzy liniami zdarzeń if (pNullable == null) { return; } var p = (PointFr)pNullable; var existing = new C5.HashSet <EventPoint>(); if (_intersections.ContainsKey(p)) { existing = _intersections[p]; // Dodaj przecięcie do słownika _intersections.Remove(p); } existing.Add(ep1); existing.Add(ep2); _intersections.Add(p, existing); if (SweepLineValue == null) { throw new ArgumentException("Wartość miotły nie może być pusta"); } var sweepLineValue = (LineFr)SweepLineValue; if (p.IsRightOf(sweepLineValue) || (sweepLineValue.Contains(p) && p.Y > currentSweepPoint.Y)) // Jeśli przecięcie jest po prawej stronie miotły lub na miotle i powyzej obecnego zdarzenia, dodaj do kolejki { var intersection = new EventPoint(p, EventPointType.Intersection, (LineSegmentFr?)null, this); EventQueue.Insert(p, intersection); } }
private readonly TreeDictionary <PointFr, C5.LinkedList <EventPoint> > _events; // Posortowana mapa punktów i odpowiadających im zdarzeń public EventQueue(C5.HashSet <LineSegmentFr> segments, SweepLine sweepLine) // Tworzy nową kolejkę zdarzeń przy użyciu zestawu odcinków { if (segments.Count <= 0) { throw new ArgumentException($"Kolekcja {nameof(segments)} nie może być pusta"); } _events = new TreeDictionary <PointFr, C5.LinkedList <EventPoint> >(new PointFrXThenYComparer()); var minY = Fraction.PositiveInfinity; var maxY = Fraction.NegativeInfinity; var minDeltaX = Fraction.PositiveInfinity; var xs = new TreeSet <Fraction>(); foreach (var s in segments) { xs.Add(s.StartPoint.X); xs.Add(s.EndPoint.X); if (s.MinY < minY) { minY = s.MinY; } if (s.MaxY > maxY) { maxY = s.MaxY; } Insert(s.StartPoint, new EventPoint(s.StartPoint, EventPointType.Left, s, sweepLine)); Insert(s.EndPoint, new EventPoint(s.EndPoint, EventPointType.Right, s, sweepLine)); } var xsArray = xs.ToArray(); for (var i = 1; i < xsArray.Length; i++) { var tempDeltaX = xsArray[i] - xsArray[i - 1]; if (tempDeltaX < minDeltaX) { minDeltaX = tempDeltaX; } } var deltaY = maxY - minY; var slope = deltaY / minDeltaX * -1; // * 1000 sweepLine.SweepLineValue = new LineFr(PointFr.Origin, new PointFr(0, 1)); // slope, PointFr.Origin sweepLine.EventQueue = this; // Porzuciłem pomysł dynamicznego zmianu nachylenia miotły, ponieważ wymagało to obliczania dużych wartości przecięć z osiami wykresu dla prostej przy użyciu Ułamków (StackOverflowException) }
public Nav2dNode findClosestAccessibleNodeInGrid(Vector3Int cellPos, Vector3 targetPos) { Nav2dNode node = null; C5.HashSet <Vector3Int> explored = new C5.HashSet <Vector3Int>(); Queue <Vector3Int> opened = new Queue <Vector3Int>(); opened.Enqueue(cellPos); // dont try to long for (int i = 0; i < 20; i++) { Vector3Int current = opened.Dequeue(); Nav2dCell cell = FindNavCellAtPosition(current); node = cell?.findClosestAccessibleNodeInCell(targetPos); if (node != null) { break; } explored.Add(current); Vector3Int[] neighbors = { current + new Vector3Int(0, 1, 0), current + new Vector3Int(0, -1, 0), current + new Vector3Int(-1, 0, 0), current + new Vector3Int(1, 0, 0) }; foreach (var n in neighbors) { if (!explored.Contains(n)) { opened.Enqueue(n); } } } return(node); }
/// <summary> /// Optimizes navmesh by deleting some triangles /// </summary> /// <param name="itm"></param> public IEnumerator OptimizeMesh() { C5.HashSet <Vector3> open = new C5.HashSet <Vector3>(); C5.HashSet <Triangle> openT = new C5.HashSet <Triangle>(); open.AddAll(vertex2Triangle.Keys); while (!open.IsEmpty) //loop through all vertices { Vector3 current = open.Pop(); if (vertex2Triangle[current].Count < 3) //if less than 3, they cannot form a "circle" { continue; } openT.Clear(); openT.AddAll(vertex2Triangle[current]); //Debug.Log("Opening " + current); //start at arbitrary triangle C5.IList <Triangle> circle = new C5.ArrayList <Triangle>(); circle.Add(openT.Pop()); //find connected circle while (openT.Count > 0) { Triangle[] circleElement = openT.Intersect(triangleIncidence[circle.Last]).ToArray(); if (circleElement.Length < 1) //no candidate - break { break; } circle.Add(circleElement[0]); openT.Remove(circle.Last); } if (openT.Count == 0 && triangleIncidence[circle.Last].Contains(circle.First)) { //Debug.Log( "Unbroken: "+current ); //check height differences bool isFlatEnough = true; foreach (Triangle trg in vertex2Triangle[current]) { foreach (Vector3 vct in trg.vertices) { if (Mathf.Abs(vct.y - current.y) > maxHeightDifference) { isFlatEnough = false; } } } if (!isFlatEnough) { continue; } ArrayList <Vector3> vctList = new ArrayList <Vector3>(); //remove old triangles foreach (Triangle trg in circle) //ToArray() is to create a buffer (to prevent concurrent modification) { RemoveTriangle(trg); for (int i = 0; i < 3; i++) { //find the CURRENT vertex - the one that is beeing removed if (trg.vertices[i] == current) { //add the NEXT to the list vctList.Add(trg.vertices[(i + 1) % 3]); } } } if (Outline.IsClockwise(vctList)) { vctList.Reverse(); } //build new triangles and add them foreach (IEnumerable <int> newTriangles in Utils.TriangulatePolygon(vctList, Enumerable.Range(0, vctList.Count)).Chunks(3)) { Triangle newTriag = new Triangle(newTriangles.Select(x => vctList[x]).ToArray()); AddTriangleByReference(newTriag); } //reopen used vertices //open.AddAll(vctList); - maybe not necessary???? //yield return new WaitForSeconds(1); yield return(null); } } }
public IEnumerable <Mesh> ExtractMeshes() { List <Mesh> meshes = new List <Mesh>(); C5.HashSet <Triangle> untouched = new C5.HashSet <Triangle>(); untouched.AddAll(triangleIncidence.Keys); Queue <Triangle> open = new Queue <Triangle>(); //the mesh that is beeing built List <Vector3> vertices = new List <Vector3>(); Dictionary <Vector3, int> vertexToIndex = new Dictionary <Vector3, int>(); List <int> indices = new List <int>(); while (!untouched.IsEmpty) { if (open.Count == 0) //empty - open on a new slot { open.Enqueue(untouched.First()); untouched.Remove(open.First()); } if (vertices.Count > 60000) //too many - split meshes { Mesh msh = new Mesh(); msh.vertices = vertices.ToArray(); msh.triangles = indices.ToArray(); meshes.Add(msh); vertices.Clear(); vertexToIndex.Clear(); indices.Clear(); } //one step of BFS Triangle current = open.Dequeue(); foreach (Triangle expand in triangleIncidence[current]) { if (untouched.Contains(expand)) { open.Enqueue(expand); untouched.Remove(expand); } } //add to mesh for (int i = 0; i < 3; i++) { if (vertexToIndex.ContainsKey(current.vertices[i])) { indices.Add(vertexToIndex[current.vertices[i]]); } else { vertices.Add(current.vertices[i]); vertexToIndex[current.vertices[i]] = vertices.Count - 1; indices.Add(vertices.Count - 1); } } } //buuild last mesh Mesh msh2 = new Mesh(); msh2.vertices = vertices.ToArray(); msh2.triangles = indices.ToArray(); meshes.Add(msh2); return(meshes); }