Ejemplo n.º 1
0
        /// <summary>
        /// Find cut lines that separates all point sets equally.
        /// Generates dcel of dual lines and generates cut lines through intersection of middle faces.
        /// </summary>
        /// <param name="a_points1"></param>
        /// <param name="a_points2"></param>
        /// <param name="a_points3"></param>
        /// <returns></returns>
        public static List <Line> FindCutLines(IEnumerable <Vector2> a_points1, IEnumerable <Vector2> a_points2,
                                               IEnumerable <Vector2> a_points3)
        {
            // obtain dual lines for game objects
            var lines1 = PointLineDual.Dual(a_points1);
            var lines2 = PointLineDual.Dual(a_points2);
            var lines3 = PointLineDual.Dual(a_points3);

            // add lines together
            var allLines = lines1.Concat(lines2.Concat(lines3));

            // calculate bounding box around line intersections with some margin
            var bBox = BoundingBoxComputer.FromLines(allLines, 10f);

            // calculate dcel for line inside given bounding box
            var dcel1 = new DCEL(lines1, bBox);
            var dcel2 = new DCEL(lines2, bBox);
            var dcel3 = new DCEL(lines3, bBox);

            // find faces in the middle of the lines vertically
            var archerFaces    = MiddleFaces(dcel1, lines1);
            var swordsmenFaces = MiddleFaces(dcel2, lines2);
            var mageFaces      = MiddleFaces(dcel3, lines3);

            // obtain cut lines for the dcel middle faces
            return(FindCutlinesInDual(archerFaces, swordsmenFaces, mageFaces));
        }
Ejemplo n.º 2
0
        public void DualOfDualTest()
        {
            var l  = new Line(0.5f, -5.2f);
            var l2 = PointLineDual.Dual(PointLineDual.Dual(l));

            Assert.AreEqual(l, l2);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Finds a number of solutions for the cut problem. Both per type of soldier and for all soldiers.
        ///
        /// NOTE: only works if the x coords of all things are all positive or all negative
        /// </summary>
        public void FindSolution()
        {
            // obtain dual lines for game objects
            m_archerLines   = PointLineDual.Dual(m_archers.Select(x => (Vector2)x.transform.position)).ToList();
            m_spearmenLines = PointLineDual.Dual(m_spearmen.Select(x => (Vector2)x.transform.position)).ToList();
            m_mageLines     = PointLineDual.Dual(m_mages.Select(x => (Vector2)x.transform.position)).ToList();

            // add lines together
            var allLines = m_archerLines.Concat(m_spearmenLines.Concat(m_mageLines));

            // calculate bounding box around line intersections with some margin
            var bBox = BoundingBoxComputer.FromLines(allLines, 10f);

            // calculate dcel for line inside given bounding box
            m_archerDcel   = new DCEL(m_archerLines, bBox);
            m_spearmenDcel = new DCEL(m_spearmenLines, bBox);
            m_mageDcel     = new DCEL(m_mageLines, bBox);

            // find faces in the middle of the lines vertically
            m_archerFaces   = HamSandwich.MiddleFaces(m_archerDcel, m_archerLines);
            m_spearmenFaces = HamSandwich.MiddleFaces(m_spearmenDcel, m_spearmenLines);
            m_mageFaces     = HamSandwich.MiddleFaces(m_mageDcel, m_mageLines);

            // obtain cut lines for the dcel middle faces and final possible cutlines
            m_solution = new DivideSolution(HamSandwich.FindCutlinesInDual(m_archerFaces),
                                            HamSandwich.FindCutlinesInDual(m_spearmenFaces),
                                            HamSandwich.FindCutlinesInDual(m_mageFaces),
                                            HamSandwich.FindCutlinesInDual(m_archerFaces, m_spearmenFaces, m_mageFaces));

            // update solution to the drawer
            m_lineDrawer.Solution = m_solution;
        }
Ejemplo n.º 4
0
        public void PointToLineTest()
        {
            var v1 = new Vector2(0.5f, 1.2f);
            var v2 = new Vector2(-0.2f, -9999.1f);

            var ret1 = PointLineDual.Dual(v1);
            var ret2 = PointLineDual.Dual(v2);

            Assert.AreEqual(new Line(0.5f, -1.2f), ret1);
            Assert.AreEqual(new Line(-0.2f, 9999.1f), ret2);
        }
Ejemplo n.º 5
0
        public void PointCollectionsTest()
        {
            var v1 = new Vector2(0.5f, 1.2f);
            var v2 = new Vector2(-0.2f, -9999.1f);

            var ret = PointLineDual.Dual(new List <Vector2>()
            {
                v1, v2
            }).ToList();

            Assert.AreEqual(2, ret.Count);
            Assert.AreEqual(new Line(0.5f, -1.2f), ret[0]);
            Assert.AreEqual(new Line(-0.2f, 9999.1f), ret[1]);
        }
Ejemplo n.º 6
0
        public void LineCollectionsTest()
        {
            var l1 = new Line(0.5f, 1.2f);
            var l2 = new Line(-0.2f, -9999.1f);

            var ret = PointLineDual.Dual(new List <Line>()
            {
                l1, l2
            }).ToList();

            Assert.AreEqual(2, ret.Count);
            Assert.IsTrue(MathUtil.EqualsEps(new Vector2(0.5f, -1.2f), ret[0]));
            Assert.IsTrue(MathUtil.EqualsEps(new Vector2(-0.2f, 9999.1f), ret[1]));
        }
Ejemplo n.º 7
0
        public void LineToPointTest()
        {
            var l1 = new Line(0.5f, 1.2f);
            var l2 = new Line(-0.2f, -9999.1f);
            var l3 = new Line(new Vector2(0f, 1.2f), new Vector2(1f, 1.7f));

            var ret1 = PointLineDual.Dual(l1);
            var ret2 = PointLineDual.Dual(l2);
            var ret3 = PointLineDual.Dual(l3);

            Assert.IsTrue(MathUtil.EqualsEps(new Vector2(0.5f, -1.2f), ret1));
            Assert.IsTrue(MathUtil.EqualsEps(new Vector2(-0.2f, 9999.1f), ret2));
            Assert.IsTrue(MathUtil.EqualsEps(ret1, ret3));
        }
Ejemplo n.º 8
0
        public static List <Line> FindCutLines(IEnumerable <Vector2> a_points)
        {
            // obtain dual lines for points
            var lines = PointLineDual.Dual(a_points);

            // calculate bounding box around line intersections with some margin
            var bBox = BoundingBoxComputer.FromLines(lines, 10f);

            // calculate dcel for line inside given bounding box
            var m_dcel = new DCEL(lines, bBox);

            // find faces in the middle of the lines vertically and calculate cut lines
            var faces = MiddleFaces(m_dcel, lines);

            return(FindCutlinesInDual(faces));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Return the Line that gives the greatest distance from all points in the dual. We calculate true seperation and not vertical seperation
        /// No error checking occurs for bounding box faces/polygons
        /// </summary>
        /// <returns>Line with greatest distance to the points encoded by the polygon boundary </returns>
        public static LineSeparation LineOfGreatestMinimumSeparationInTheDual(Polygon2D polygon, bool a_isBoundingBoxFace)
        {
            // copy for safety
            var poly = new Polygon2D(polygon.Vertices);

            if (!poly.IsConvex())
            {
                throw new GeomException("Only support computing lines of greatest seperation for convex polygons");
            }

            if (!poly.IsClockwise())
            {
                poly = new Polygon2D(poly.Vertices.Reverse());
            }

            var upperhull = ConvexHull.ComputeUpperHull(poly).ToList();
            var lowerhull = ConvexHull.ComputeLowerHull(poly).ToList();

            if (a_isBoundingBoxFace)
            {
                //Check if the boundingboxface has only 2 real neighbouring lines(in the dual) and return the bisector (in the primal) in this case
                var reallines = poly.Segments
                                .Select(seg => seg.Line)
                                .Where(line => !line.IsHorizontal && !line.IsVertical)
                                .ToList();

                if (reallines.Count < 2)
                {
                    throw new GeomException("Found impossibly low amount of real lines");
                }
                else if (reallines.Count == 2)
                {
                    //The two reallines are two points in the primal plane
                    // get intersection
                    // Assumes general positions of initial points
                    var averagepoint         = (PointLineDual.Dual(reallines[0]) + PointLineDual.Dual(reallines[1])) / 2;
                    var lineTroughBothPoints = PointLineDual.Dual(reallines[0].Intersect(reallines[1]).Value);
                    var perpLineSlope        = -1 / lineTroughBothPoints.Slope;
                    var perpPoint            = averagepoint + Vector2.right + Vector2.up * perpLineSlope;

                    return(new LineSeparation(new Line(averagepoint, perpPoint), 0));

                    //we choose separtion 0 because a line with three constraints in the outer boundingboxface is more important?
                    //TODO this seems untrue, explictly calculate seperation (Wrt to all soldier??)
                }
                //Otherwise we return the regular bisector
            }


            //zero is the starting corner, 1 is the first interesting point
            var upperhullIterator = 0;
            var lowerhullIterator = 0;
            var candidatePoint    = new Vector2(0, 0); //dummy value
            var currentSeparation = 0f;

            float currentx = upperhull[0].x;
            float nextx;
            float currentheight = 0;
            float nextheight;

            LineSegment upperSegment = null;
            LineSegment lowerSegment = null;

            Action <float, float> testCandidatePoint = delegate(float testx, float testheight)
            {
                var trueSeperation = Mathf.Sin(Mathf.PI / 2 - Mathf.Abs(Mathf.Atan(testx))) * testheight; //Atan(x) is the angle a line of slope x makes
                if (trueSeperation > currentSeparation)
                {
                    candidatePoint    = new Vector2(testx, (upperSegment.Y(testx) + lowerSegment.Y(testx)) / 2);
                    currentSeparation = trueSeperation;
                    return;
                }
            };

            //initialize segments
            lowerSegment = new LineSegment(lowerhull[0], lowerhull[1]);
            upperSegment = new LineSegment(upperhull[0], upperhull[1]);

            //Break when one of the two lists is completly traversed
            while (upperhullIterator < upperhull.Count - 1 && lowerhullIterator < lowerhull.Count - 1)
            {
                //The part between currentx(exclusive) and nextx(inclusive) is under scrutiny
                //we advance the segment that ends on the smallest x
                if (upperhull[upperhullIterator].x < lowerhull[lowerhullIterator].x)
                {
                    upperhullIterator++;
                    upperSegment = new LineSegment(upperhull[upperhullIterator - 1], upperhull[upperhullIterator]);
                }
                else
                {
                    lowerhullIterator++;
                    lowerSegment = new LineSegment(lowerhull[lowerhullIterator - 1], lowerhull[lowerhullIterator]);
                }

                if (lowerSegment.IsVertical || upperSegment.IsVertical)
                {
                    continue; //skip this iteration
                }

                nextx = Mathf.Min(upperSegment.XInterval.Max, lowerSegment.XInterval.Max);

                nextheight = upperSegment.Y(nextx) - lowerSegment.Y(nextx);
                if (nextheight < 0)
                {
                    throw new GeomException();
                }
                testCandidatePoint(nextx, nextheight);

                //also points inbetween vertices
                float heightchange = (nextheight - currentheight) / (nextx - currentx);
                float baseheigth   = nextheight - nextx * heightchange;

                float candidatex = heightchange / baseheigth;
                if (new FloatInterval(currentx, nextx).Contains(candidatex))
                {
                    var candidateheigth = baseheigth + heightchange * candidatex;
                    testCandidatePoint(candidatex, candidateheigth);
                }

                //save variables for next iteration
                currentheight = nextheight;
                currentx      = nextx;
            }

            return(new LineSeparation(PointLineDual.Dual(candidatePoint), currentSeparation));
        }