Ejemplo n.º 1
0
        /// <summary>
        /// Dla podanych współrzędnych ołtarza i murów metoda zwraca informację czy istnieje półprosta o początku
        /// w ołtarzu nie przecinająca żadnego muru.
        /// (2pkt)
        /// </summary>
        /// <remarks>
        /// Nie należy liczyć bezpośrednio żadnych kątów (funkcje trygonometryczne liczą się powoli)
        /// Można zastosować następujący algorytm
        ///
        ///    A) przygotowanie danych
        ///    Na podstawie tablicy murów (odcinków) utworzyć tablicę punktów (końców odcinków).
        ///    Utworzyć też Dictionary indeksowane punktami i wypełnione wartościami +1 dla "wcześniejszego końca odcinka" i -1 dla "późniejszego końca odcinka".
        ///    "Wcześniejszy koniec odcinka" to koniec, dla którego prosta przechodząca przez ten koniec tworzy mniejszy kąt z osia OX
        ///    niż analogiczna prosta przechodząca przez drugi koniec (ten drugi koniec to "póżniejszy koniec"). Oczywiście nie liczymy bezpośrednio żadnych kątów !!!.
        ///    Policzyć ile murów (odcinków) przecina się z półprostą (długim odcinkiem) zaczepioną w ołtarzu i równoległą do osi OX
        ///
        ///    B) posortować tablicę punktów (końców odcinków) według kąta jaki tworzą odcinki o początku w ołtarzu i końcu w danym punkcie z osią OX
        ///       (skorzystać z biblioteki geom.cs)
        ///
        ///    C) obliczenia
        ///    przetwarzać punkty w kolejności wynikającej z posortowania w czesci B
        ///    dla każdego z punktów zmniejszać bądź zwiekszać licznik przecięć (odbiczony w części A) zależnie od tego czy punkt jest wcześniejszym czy późniejszym końcem odcinka
        ///    (korzystać z przygotowanego Dictionary). Zastanowić się co oznacza wartość licznika równa 0.
        ///
        ///    Uwaga: Nie przejmować się przypadkami szczególnymi (np. ołtarz i końce dwóch murów leżące na jednej prostej) w testach ich nie będzie.
        /// </remarks>
        /// <param name="altar"> Współrzędne ołtarza</param>
        /// <param name="walls">zbiór murów (odcinków)</param>
        /// <returns>true jeśli nie istnieje prosta nieprzecinająca muru, false jeśli taka prosta istnieje</returns>
        public static bool ChineeseAltars(Point altar, Segment[] walls)
        {
            var     points        = new List <Point>();
            var     type          = new Dictionary <Point, int>();
            Segment OX            = new Segment(altar, new Point(double.MaxValue, altar.y));
            int     intersections = 0;

            foreach (Segment wall in walls)
            {
                points.Add(wall.ps);
                points.Add(wall.pe);
                Segment startSeg            = new Segment(altar, new Point(wall.ps.x, wall.ps.y));
                Point   endSeg              = new Point(wall.pe.x, wall.pe.y);
                int     startSegOrientation = -startSeg.Direction(endSeg);
                type.Add(wall.ps, startSegOrientation);
                type.Add(wall.pe, -startSegOrientation);
                if (Geometry.Intersection(wall, OX))
                {
                    intersections++;
                }
            }
            Point[] sorted = Geometry.AngleSort(altar, points.ToArray());
            foreach (Point point in sorted)
            {
                intersections -= type[point];
                if (intersections == 0)
                {
                    break;
                }
            }
            return(intersections != 0);
        }
Ejemplo n.º 2
0
        public static void QuickHullRec(Point A, Point B, Point[] S, ref List <Point> L)
        {
            int    maxIdx = 0;
            double dist   = 0.0;
            double _A     = A.y - B.y; // zmiana znaku
            double _B     = B.x - A.x;
            double _C     = A.y * (B.x - A.x) - A.x * (B.y - A.y);

            for (int i = 0; i < S.Length; i++)
            {
                if (Math.Abs(_A * S[i].x + _B * S[i].y + _C) > dist)
                {
                    maxIdx = i;
                    dist   = Math.Abs(_A * S[i].x + _B * S[i].y + _C);
                }
            }

            Point        C  = S[maxIdx];
            Segment      AC = new Segment(A, C);
            Segment      CB = new Segment(C, B);
            List <Point> S1 = new List <Point>();
            List <Point> S2 = new List <Point>();

            for (int i = 0; i < S.Length; i++)
            {
                if (AC.Direction(S[i]) == Geometry.ClockWise)
                {
                    S1.Add(S[i]);
                }
                else if (CB.Direction(S[i]) == Geometry.ClockWise)
                {
                    S2.Add(S[i]);
                }
            }

            if (S1.Count != 0)
            {
                QuickHullRec(A, C, S1.ToArray(), ref L);
            }
            L.Add(C);
            if (S2.Count != 0)
            {
                QuickHullRec(C, B, S2.ToArray(), ref L);
            }

            #endregion
#endif
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Dla podanych współrzędnych ołtarza i murów metoda zwraca informację czy istnieje półprosta o początku
        /// w ołtarzu nie przecinająca żadnego muru.
        /// (2pkt)
        /// </summary>
        /// <remarks>
        /// Nie należy liczyć bezpośrednio żadnych kątów (funkcje trygonometryczne liczą się powoli)
        /// Można zastosować następujący algorytm
        ///
        ///    A) przygotowanie danych
        ///    Na podstawie tablicy murów (odcinków) utworzyć tablicę punktów (końców odcinków).
        ///    Utworzyć też Dictionary indeksowane punktami i wypełnione wartościami +1 dla "wcześniejszego końca odcinka" i -1 dla "późniejszego końca odcinka".
        ///    "Wcześniejszy koniec odcinka" to koniec, dla którego prosta przechodząca przez ten koniec tworzy mniejszy kąt z osia OX
        ///    niż analogiczna prosta przechodząca przez drugi koniec (ten drugi koniec to "póżniejszy koniec"). Oczywiście nie liczymy bezpośrednio żadnych kątów !!!.
        ///    Policzyć ile murów (odcinków) przecina się z półprostą (długim odcinkiem) zaczepioną w ołtarzu i równoległą do osi OX
        ///
        ///    B) posortować tablicę punktów (końców odcinków) według kąta jaki tworzą odcinki o początku w ołtarzu i końcu w danym punkcie z osią OX
        ///       (skorzystać z biblioteki geom.cs)
        ///
        ///    C) obliczenia
        ///    przetwarzać punkty w kolejności wynikającej z posortowania w czesci B
        ///    dla każdego z punktów zmniejszać bądź zwiekszać licznik przecięć (odbiczony w części A) zależnie od tego czy punkt jest wcześniejszym czy późniejszym końcem odcinka
        ///    (korzystać z przygotowanego Dictionary). Zastanowić się co oznacza wartość licznika równa 0.
        ///
        ///    Uwaga: Nie przejmować się przypadkami szczególnymi (np. ołtarz i końce dwóch murów leżące na jednej prostej) w testach ich nie będzie.
        /// </remarks>
        /// <param name="altar"> Współrzędne ołtarza</param>
        /// <param name="walls">zbiór murów (odcinków)</param>
        /// <returns>true jeśli nie istnieje prosta nieprzecinająca muru, false jeśli taka prosta istnieje</returns>
        public static bool ChineeseAltars(Point altar, Segment[] walls)
        {
            List <Point>            wallsPointsList  = new List <Point>();
            Dictionary <Point, int> pointsDictionary = new Dictionary <Point, int>();
            Point   xMax                   = new Point(walls.Max(wall => Math.Max(wall.pe.x, wall.ps.x)), 0);
            Segment xAxisAtAltar           = new Segment(altar, new Point(xMax.x, altar.y));
            int     wallsIntersectingXAxis = 0;

            foreach (Segment wall in walls)
            {
                wallsPointsList.Add(wall.ps);
                wallsPointsList.Add(wall.pe);

                if (Point.CrossProduct(wall.pe, xMax) > Point.CrossProduct(wall.ps, xMax))
                {
                    pointsDictionary.Add(wall.pe, -1);
                    pointsDictionary.Add(wall.ps, 1);
                }
                else
                {
                    pointsDictionary.Add(wall.pe, 1);
                    pointsDictionary.Add(wall.ps, -1);
                }

                if (Geometry.Intersection(xAxisAtAltar, wall))
                {
                    wallsIntersectingXAxis++;
                }
            }

            Point[] sortedWallsPoints = Geometry.AngleSort(altar, wallsPointsList.ToArray());

            foreach (Point wallPoint in sortedWallsPoints)
            {
                if (wallsIntersectingXAxis == 0)
                {
                    return(false);
                }
                wallsIntersectingXAxis += pointsDictionary[wallPoint];
            }

            return(wallsIntersectingXAxis != 0);
        }
Ejemplo n.º 4
0
        static void ChineeseAltarTests()
        {
            Random r = new Random(211);

            Console.WriteLine("Chińskie ołtarze : ");
            List <Segment> t3 = new List <Segment>();

            for (int i = 0; i < 100; i++)
            {
                Segment ns = new Segment(new Point(r.Next() % 100 - 50, r.Next() % 100 - 50), new Point(r.Next() % 100 - 50, r.Next() % 100 - 50));
                t3.Add(ns);
            }
            var tests = new[] {
                new
                {
                    Altar = new Point(0, 0),
                    Walls = new [] {
                        new Segment(new Point(-10, 10), new Point(-10, -10)),
                        new Segment(new Point(10, 10), new Point(10, -10)),
                        new Segment(new Point(-9, 2), new Point(9, 2)),
                        new Segment(new Point(-9, -2), new Point(9, -2))
                    },
                    Result = true
                },
                new
                {
                    Altar = new Point(0, 0),
                    Walls = new [] {
                        new Segment(new Point(-11, 2.2), new Point(-11, -10)),
                        new Segment(new Point(10, 10), new Point(10, -10)),
                        new Segment(new Point(-9, 2), new Point(9, 2)),
                        new Segment(new Point(-9, -2), new Point(9, -2))
                    },
                    Result = false
                },
                new
                {
                    Altar = new Point(5, 1.5),
                    Walls = new [] {
                        new Segment(new Point(-11, 2.2), new Point(-11, -10)),
                        new Segment(new Point(10, 10), new Point(10, -10)),
                        new Segment(new Point(-9, 2), new Point(9, 2)),
                        new Segment(new Point(-9, -2), new Point(9, -2))
                    },
                    Result = true
                },
                new
                {
                    Altar = new Point(1, 1),
                    Walls = new [] {
                        new Segment(new Point(-11, 2.2), new Point(-11, -10)),
                        new Segment(new Point(10, 10), new Point(10, 1.1)),
                        new Segment(new Point(10, 0.9), new Point(10, -10)),
                        new Segment(new Point(-9, 2), new Point(9, 2)),
                        new Segment(new Point(-9, -2), new Point(9, -2))
                    },
                    Result = false
                },
                new
                {
                    Altar  = new Point(0, 0),
                    Walls  = t3.ToArray(),
                    Result = true
                },
                new
                {
                    Altar = new Point(3, 2),
                    Walls = new []
                    {
                        new Segment(new Point(1, 2), new Point(0, 3)),
                        new Segment(new Point(1, 3), new Point(5, 3)),
                        new Segment(new Point(4, 4), new Point(2, 5)),
                        new Segment(new Point(0, 2), new Point(2, 4))
                    },
                    Result = false
                },
                new
                {
                    Altar = new Point(3, 4),
                    Walls = new []
                    {
                        new Segment(new Point(2, 6), new Point(2, 3)),
                        new Segment(new Point(4, 3), new Point(4, 5))
                    },
                    Result = false
                },
                new
                {
                    Altar = new Point(3, 3),
                    Walls = new []
                    {
                        new Segment(new Point(2, 4), new Point(4, 4))
                    },
                    Result = false
                },
                new
                {
                    Altar = new Point(4, 4),
                    Walls = new []
                    {
                        new Segment(new Point(0, 3), new Point(2, 1)),
                        new Segment(new Point(5, 1), new Point(7, 3)),
                        new Segment(new Point(2, 3), new Point(5, 3)),
                        new Segment(new Point(1, 3), new Point(1, 6)),
                        new Segment(new Point(2, 5), new Point(3.5, 7)),
                        new Segment(new Point(5, 8), new Point(7, 6)),
                        new Segment(new Point(6, 3), new Point(6, 5))
                    },
                    Result = false
                },
                new
                {
                    Altar = new Point(4, 4),
                    Walls = new []
                    {
                        new Segment(new Point(0, 3), new Point(2, 1)),
                        new Segment(new Point(5, 1), new Point(7, 3)),
                        new Segment(new Point(2, 3), new Point(5, 3)),
                        new Segment(new Point(1, 3), new Point(1, 6)),
                        new Segment(new Point(2, 5), new Point(4, 7)),
                        new Segment(new Point(5, 8), new Point(7, 6)),
                        new Segment(new Point(6, 3), new Point(6, 5.5)),
                        new Segment(new Point(3.5, 9), new Point(6, 9))
                    },
                    Result = true
                },
                new
                {
                    Altar = new Point(3, 4),
                    Walls = new []
                    {
                        new Segment(new Point(4, 2.8), new Point(4, 5.2)),
                        new Segment(new Point(1, 2), new Point(5, 2)),
                        new Segment(new Point(1, 6), new Point(5, 6)),
                        new Segment(new Point(2, 2.8), new Point(2, 5.2)),
                    },
                    Result = true
                },
            };



            for (int i = 0; i < tests.Length; i++)
            {
                var    t       = tests[i];
                bool   success = false;
                string message = "";
                try
                {
                    bool result = Lab12.ChineeseAltars(t.Altar, t.Walls);
                    success = CheckChineeseAltarResult(result, t.Result);
                }
                catch (Exception e)
                {
                    success = false;
                    message = e.Message;
                }
                if (success)
                {
                    Console.WriteLine("{0} : {1} ", i + 1, "SUKCES");
                }
                else
                {
                    Console.WriteLine("{0} : {1} - {2}", i + 1, "BŁĄD", message);
                }
            }



            Console.WriteLine();
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Znajduje otoczkę wypukłą dla punktów.
        /// Można zastosować dowolny algorytm liczenia otoczki omówiony na wykłądzie
        /// </summary>
        /// <param name="points">Tablica punktów</param>
        /// <returns>Tablica kolejnych punktów należących do otoczki</returns>
        public static Point[] ConvexHull(Point[] p)
        {
#if Graham
            #region Graham

            int minIdx = 0;
            for (int i = 1; i < p.Length; i++)
            {
                if (p[i].y < p[minIdx].y || p[i].y == p[minIdx].y && p[i].x < p[minIdx].x)
                {
                    minIdx = i;
                }
            }

            Point tmp = p[0];
            p[0]      = p[minIdx];
            p[minIdx] = tmp;

            p = Geometry.AngleSort(p[0], p);
            //Func<double, double> Sqr = ((a) => a * a);
            //Func<Point, Point, double> QuadraticDist = (a, b) => (Sqr(a.x - b.x) + Sqr(a.y - b.y));
            //p = Geometry.AngleSort(p[0], p, (a, b) =>
            //{
            //    double da = QuadraticDist(p[0], a);
            //    double db = QuadraticDist(p[0], b);
            //    if (da != db)
            //        return (da < db ? -1 : 1);
            //    else
            //        return 0;
            //});

            Segment line  = new Segment(p[0], p[1]);
            var     stack = new Stack <Point>();
            stack.Push(p[0]);
            stack.Push(p[1]);
            for (int i = 2; i <= p.Length; ++i) // dodatkowa iteracja
            {
                int j = (i % p.Length);

                while (stack.Count > 2 && line.Direction(p[j]) != Geometry.AntiClockWise)
                {
                    stack.Pop();
                    line.pe = stack.Pop();  // top
                    line.ps = stack.Peek(); // below
                    stack.Push(line.pe);
                }

                if (stack.Count == 2 && line.Direction(p[j]) != Geometry.AntiClockWise) // trzy punkty wspolliniowe
                {
                    stack.Pop();
                }

                stack.Push(p[j]);
                line.ps = line.pe;  // below
                line.pe = p[j];     // top
            }

            stack.Pop(); // wyrzucamy powtorzony pierwszy punkt
            return(stack.ToArray());

            #endregion
#elif Jarvis
            #region Jarvis

            int minIdx = 0;
            for (int i = 1; i < p.Length; i++)
            {
                if (p[i].y < p[minIdx].y || p[i].y == p[minIdx].y && p[i].x < p[minIdx].x)
                {
                    minIdx = i;
                }
            }

            Point tmp = p[0];
            p[0]      = p[minIdx];
            p[minIdx] = tmp;

            Segment       line  = new Segment(new Point(int.MinValue, 0), new Point(0, int.MaxValue)); // cokolwiek
            Stack <Point> stack = new Stack <Point>();
            stack.Push(p[0]);

            while (true)
            {
                int best = -1;
                for (int k = 0; k < p.Length; k++)
                {
                    if (best == -1 ||
                        line.Direction(p[k]) == Geometry.ClockWise ||
                        line.Direction(p[k]) == Geometry.Collinear &&
                        Point.Distance(stack.Peek(), p[best]) < Point.Distance(stack.Peek(), p[k]))
                    {
                        best = k;
                    }
                    line.ps = stack.Peek();
                    line.pe = p[best];
                }
                if (best == 0)
                {
                    return(stack.ToArray());
                }
                stack.Push(p[best]);
            }

            #endregion
#elif QuickHull
            #region QuickHull

            int minIdx = 0;
            int maxIdx = 0;
            for (int i = 1; i < p.Length; i++)
            {
                if (p[i].x < p[minIdx].x || p[i].x == p[minIdx].x && p[i].y < p[minIdx].y)
                {
                    minIdx = i;
                }
                if (p[i].x > p[maxIdx].x || p[i].x == p[maxIdx].x && p[i].y > p[maxIdx].y)
                {
                    maxIdx = i;
                }
            }

            Point        A  = p[minIdx];
            Point        B  = p[maxIdx];
            Segment      AB = new Segment(A, B);
            List <Point> L  = new List <Point>();
            List <Point> S1 = new List <Point>();
            List <Point> S2 = new List <Point>();
            for (int i = 0; i < p.Length; i++)
            {
                if (AB.Direction(p[i]) == Geometry.ClockWise)
                {
                    S1.Add(p[i]);
                }
                else if (AB.Direction(p[i]) == Geometry.AntiClockWise)
                {
                    S2.Add(p[i]);
                }
            }

            L.Add(A);
            QuickHullRec(A, B, S1.ToArray(), ref L);
            L.Add(B);
            QuickHullRec(B, A, S2.ToArray(), ref L);

            return(L.ToArray());
        }