private static bool IsEarTip(IList <Vector2> polygon, PolygonVertex vertex, IList <PolygonVertex> reflexVertices)
    {
        if (vertex.IsReflex)
        {
            return(false);
        }

        Vector2 a = polygon[vertex.Prev.Index];
        Vector2 b = polygon[vertex.Index];
        Vector2 c = polygon[vertex.Next.Index];

        foreach (var reflexVertex in reflexVertices)
        {
            int index = reflexVertex.Index;

            if (index == vertex.Prev.Index || index == vertex.Next.Index)
            {
                continue;
            }

            if (TriangleContains(a, b, c, polygon[index]))
            {
                return(false);
            }
        }

        return(true);
    }
    private static float WindingValue(IList <Vector2> polygon, PolygonVertex vertex)
    {
        Vector2 a = polygon[vertex.Prev.Index];
        Vector2 b = polygon[vertex.Index];
        Vector2 c = polygon[vertex.Next.Index];

        return((float)((b.x - a.x) * (c.y - b.y) - (c.x - b.x) * (b.y - a.y)));
    }
Beispiel #3
0
        /// <remarks>v0 is connected to v1 and v1 is connected to v2</remarks>
        private static Vector3 GetVertexNormal(PolygonVertex v0, PolygonVertex v1, PolygonVertex v2)
        {
            var ba = v0.Position - v1.Position;
            var bc = v2.Position - v1.Position;

            ba.Normalize();
            bc.Normalize();
            return(Vector3.Cross(ba, bc));
        }
Beispiel #4
0
        /// <remarks>v0 is connected to v1 and v1 is connected to v2</remarks>
        private void AddFaceFrom(List <PolygonFace> faces, PolygonVertex v0, PolygonVertex v1, PolygonVertex v2)
        {
            //search face
            foreach (var face in faces)
            {
                if (face.Contains(v0) && face.Contains(v1) && face.Contains(v2))
                {
                    return;
                }
            }

            var normal = GetVertexNormal(v0, v1, v2);

            for (int i = 0; i < 3; i++)
            {
                var v3 = v2.Edges[i];
                if (v3 == v1)
                {
                    continue;           // don't walk back
                }
                var normal2 = GetVertexNormal(v1, v2, v3);
                var dot     = Vector3.Dot(normal, normal2);
                if (dot < 0.85f)
                {
                    continue;
                }
                for (int k = 0; k < 3; k++)
                {
                    var v4 = v3.Edges[k];
                    if (v4 == v2)
                    {
                        continue;           // don't walk back
                    }
                    var normal3 = GetVertexNormal(v2, v3, v4);
                    dot = Vector3.Dot(normal, normal3);
                    if (dot < 0.85f)
                    {
                        continue;
                    }
                    for (int j = 0; j < 3; j++)
                    {
                        if (v0 == v4.Edges[j])
                        {
                            var face = new PolygonFace(normal);
                            face.Vertices.Add(v0);
                            face.Vertices.Add(v1);
                            face.Vertices.Add(v2);
                            face.Vertices.Add(v3);
                            face.Vertices.Add(v4);
                            faces.Add(face);
                        }
                    }
                }
            }

            return;
        }
Beispiel #5
0
 public bool AddVertex(PolygonVertex v)
 {
     if (PolyVertexCache.ContainsKey(v))
     {
         return(false);
     }
     PolyVertexCache.Add(v, PolyVertextCount++);
     return(true);
 }
Beispiel #6
0
    /// <summary>
    /// ランチャーの解析
    /// </summary>
    public List <Launcher> ParseLauncher(float tolerance = 1f)
    {
        List <PolygonVertex> vertices = polygon.GetPolygonVertices();
        int             size          = vertices.Count;
        List <Launcher> launchers     = new List <Launcher>();

        for (int i = 0; i < size; ++i)
        {
            PolygonVertex p1       = vertices[(i + 1) % size];
            PolygonVertex p2       = vertices[(i + 2) % size];
            float         sumAngle = p1.angle + p2.angle;

            if (180f - tolerance < sumAngle && sumAngle < 180f + tolerance)
            {
                PolygonVertex p0 = vertices[i];
                PolygonVertex p3 = vertices[(i + 3) % size];
                //座標
                Vector2 point = (p2.point - p1.point) * 0.5f + p1.point;
                //角度
                float angle = GeomUtil.TwoPointAngle(p0.point, p1.point);
                //砲身長
                float barrel0 = (p1.point - p0.point).magnitude;
                float barrel1 = (p3.point - p2.point).magnitude;
                float barrel  = (barrel0 + barrel1) * 0.5f;
                //口径
                Line    l1           = Line.FromPoints(p0.point, p1.point);
                Line    l2           = Line.FromPoints(p2.point, GeomUtil.RotateVector2(p3.point - p2.point, 90f) + p2.point);          //l1の垂直線
                Vector2 intersection = Vector2.zero;
                l1.GetIntersectionPoint(l2, ref intersection);
                float caliber = (intersection - p2.point).magnitude;

                launchers.Add(new Launcher(point, angle, barrel, caliber));
            }
        }
        return(launchers);
    }
 /// <remarks>v0 is connected to v1 and v1 is connected to v2</remarks>
 private static Vector3 GetVertexNormal(PolygonVertex v0, PolygonVertex v1, PolygonVertex v2)
 {
     var ba = v0.Position - v1.Position;
     var bc = v2.Position - v1.Position;
     ba.Normalize();
     bc.Normalize();
     return Vector3.Cross(ba, bc);
 }
        /// <remarks>v0 is connected to v1 and v1 is connected to v2</remarks>
        private void AddFaceFrom(List<PolygonFace> faces, PolygonVertex v0, PolygonVertex v1, PolygonVertex v2)
        {            
            //search face 
            foreach (var face in faces)
            {
                if (face.Contains(v0) && face.Contains(v1) && face.Contains(v2))
                    return;
            }
            
            var normal = GetVertexNormal(v0, v1, v2);

            for (int i = 0; i < 3; i++)
            {
                var v3 = v2.Edges[i];
                if (v3 == v1) continue; // don't walk back
                var normal2 = GetVertexNormal(v1, v2, v3);
                var dot = Vector3.Dot(normal, normal2);
                if (dot < 0.85f) continue;
                for (int k = 0; k < 3; k++)
                {
                    var v4 = v3.Edges[k];
                    if (v4 == v2) continue; // don't walk back
                    var normal3 = GetVertexNormal(v2, v3, v4);
                    dot = Vector3.Dot(normal, normal3);
                    if (dot < 0.85f) continue;
                    for (int j = 0; j < 3; j++)
                    {
                        if (v0 == v4.Edges[j])
                        {
                            var face = new PolygonFace(normal);
                            face.Vertices.Add(v0);
                            face.Vertices.Add(v1);
                            face.Vertices.Add(v2);
                            face.Vertices.Add(v3);
                            face.Vertices.Add(v4);
                            faces.Add(face);
                        }
                    }
                }
            }

            return;
        }
Beispiel #9
0
        /// <summary>
        /// Find spreadsheets areas from cells.
        /// <para>Based on O'Rourke's `Uniqueness of orthogonal connect-the-dots`.</para>
        /// </summary>
        /// <param name="cells"></param>
        public static List <TableRectangle> FindSpreadsheetsFromCells(List <TableRectangle> cells)
        {
            // via: http://stackoverflow.com/questions/13746284/merging-multiple-adjacent-rectangles-into-one-polygon
            List <TableRectangle>           rectangles = new List <TableRectangle>();
            HashSet <PdfPoint>              pointSet   = new HashSet <PdfPoint>();
            Dictionary <PdfPoint, PdfPoint> edgesH     = new Dictionary <PdfPoint, PdfPoint>();
            Dictionary <PdfPoint, PdfPoint> edgesV     = new Dictionary <PdfPoint, PdfPoint>();
            int i = 0;

            cells = new List <TableRectangle>(new HashSet <TableRectangle>(cells));

            Utils.Sort(cells, new TableRectangle.ILL_DEFINED_ORDER());

            foreach (TableRectangle cell in cells)
            {
                foreach (PdfPoint pt in cell.Points)
                {
                    if (pointSet.Contains(pt))
                    {
                        pointSet.Remove(pt); // shared vertex, remove it
                    }
                    else
                    {
                        pointSet.Add(pt);
                    }
                }
            }

            // X first sort
            List <PdfPoint> pointsSortX = new List <PdfPoint>(pointSet);

            pointsSortX.Sort(new X_FIRST_POINT_COMPARER());

            // Y first sort
            List <PdfPoint> pointsSortY = new List <PdfPoint>(pointSet);

            pointsSortY.Sort(new POINT_COMPARER());

            while (i < pointSet.Count)
            {
                float currY = (float)pointsSortY[i].Y;
                while (i < pointSet.Count && Utils.Feq(pointsSortY[i].Y, currY))
                {
                    edgesH[pointsSortY[i]]     = pointsSortY[i + 1];
                    edgesH[pointsSortY[i + 1]] = pointsSortY[i];
                    i += 2;
                }
            }

            i = 0;
            while (i < pointSet.Count)
            {
                float currX = (float)pointsSortX[i].X;
                while (i < pointSet.Count && Utils.Feq(pointsSortX[i].X, currX))
                {
                    edgesV[pointsSortX[i]]     = pointsSortX[i + 1];
                    edgesV[pointsSortX[i + 1]] = pointsSortX[i];
                    i += 2;
                }
            }

            // Get all the polygons
            List <List <PolygonVertex> > polygons = new List <List <PolygonVertex> >();
            PdfPoint nextVertex;

            while (edgesH.Count != 0)
            {
                List <PolygonVertex> polygon = new List <PolygonVertex>();
                PdfPoint             first   = edgesH.Keys.First();
                polygon.Add(new PolygonVertex(first, Direction.HORIZONTAL));
                edgesH.Remove(first);

                while (true)
                {
                    PolygonVertex curr = polygon[polygon.Count - 1];
                    PolygonVertex lastAddedVertex;
                    if (curr.direction == Direction.HORIZONTAL)
                    {
                        nextVertex = edgesV[curr.point];
                        edgesV.Remove(curr.point);
                        lastAddedVertex = new PolygonVertex(nextVertex, Direction.VERTICAL);
                        polygon.Add(lastAddedVertex);
                    }
                    else
                    {
                        nextVertex = edgesH[curr.point];
                        edgesH.Remove(curr.point);
                        lastAddedVertex = new PolygonVertex(nextVertex, Direction.HORIZONTAL);
                        polygon.Add(lastAddedVertex);
                    }

                    if (lastAddedVertex.Equals(polygon[0]))
                    {
                        // closed polygon
                        polygon.RemoveAt(polygon.Count - 1);
                        break;
                    }
                }

                foreach (PolygonVertex vertex in polygon)
                {
                    edgesH.Remove(vertex.point);
                    edgesV.Remove(vertex.point);
                }
                polygons.Add(polygon);
            }

            // calculate axis-aligned minimum area rectangles for each found polygon
            foreach (List <PolygonVertex> poly in polygons)
            {
                double top    = double.MinValue;    //java.lang.Float.MAX_VALUE;
                double left   = double.MaxValue;    //java.lang.Float.MAX_VALUE;
                double bottom = double.MaxValue;    //java.lang.Float.MIN_VALUE;
                double right  = double.MinValue;    //java.lang.Float.MIN_VALUE;
                foreach (PolygonVertex pt in poly)
                {
                    top    = Math.Max(top, pt.point.Y);    // Min
                    left   = Math.Min(left, pt.point.X);
                    bottom = Math.Min(bottom, pt.point.Y); // Max
                    right  = Math.Max(right, pt.point.X);
                }
                rectangles.Add(new TableRectangle(new PdfRectangle(left, bottom, right, top))); // top, left, right - left, bottom - top));
            }

            return(rectangles);
        }
    /// <summary>
    /// Splits a polygon into triangles.
    /// </summary>
    /// <param name="polygon">
    /// Polygon to be split.
    /// </param>
    /// <returns>
    /// List of vertices in input polygon that form triangles (will either
    /// be empty or have count that is a factor of 3). Triangles will be clockwise if
    /// polygon is clockwise and counter-clockwise if polygon is counter-clockwise.
    /// </returns>
    public static IEnumerable <int> Triangulate(IList <Vector2> polygon)
    {
        int N = polygon.Count;

        // Not a polygon.
        if (N <= 2)
        {
            return(new int[] { });
        }

        IList <int> triangles = new List <int>();

        // Initialize leftmost and vertices for polygon
        IList <PolygonVertex> vertices = polygon.Select(v => new PolygonVertex()).ToList();
        int iLeftMost = 0;

        for (int i = 0; i < N; i++)
        {
            int iPrev = MathUtil.Mod(i - 1, N);
            int iNext = MathUtil.Mod(i + 1, N);

            // Init polygon vertex
            vertices[i].Index        = i;
            vertices[i].Prev         = vertices[iPrev];
            vertices[i].Next         = vertices[iNext];
            vertices[i].Prev.Index   = iPrev;
            vertices[i].Next.Index   = iNext;
            vertices[i].WindingValue = WindingValue(polygon, vertices[i]);
            vertices[i].IsReflex     = false;

            // Update leftmost for polygon
            Vector2 p  = polygon[i];
            Vector2 lm = polygon[iLeftMost];

            if (p.x < lm.x || (p.x == lm.x && p.y < lm.y))
            {
                iLeftMost = i;
            }
        }

        // Check if polygon is counter-clockwise
        bool isCcw = vertices[iLeftMost].WindingValue > 0.0f;

        // Initialize list of reflex vertices
        IList <PolygonVertex> reflexVertices = new List <PolygonVertex>();

        foreach (var vertex in vertices)
        {
            if (IsReflex(isCcw, vertex))
            {
                vertex.IsReflex = true;
                reflexVertices.Add(vertex);
            }
        }

        // Perform triangulation
        int skipped   = 0;              // Number of consecutive vertices skipped
        int nVertices = vertices.Count; // Number of vertices left in polygon

        PolygonVertex current = vertices[0];

        // While polygon not a triangle
        while (nVertices > 3)
        {
            PolygonVertex prev = current.Prev;
            PolygonVertex next = current.Next;

            if (IsEarTip(polygon, current, reflexVertices))
            {
                // Add this ear to list of triangles
                triangles.Add(prev.Index);
                triangles.Add(current.Index);
                triangles.Add(next.Index);

                // Remove this ear from polygon
                prev.Next = next;
                next.Prev = prev;

                // Re-calculate reflexivity of adjacent vertices
                PolygonVertex[] adjacent = { prev, next };
                foreach (var vertex in adjacent)
                {
                    if (vertex.IsReflex)
                    {
                        vertex.WindingValue = WindingValue(polygon, vertex);
                        vertex.IsReflex     = IsReflex(isCcw, vertex);

                        if (!vertex.IsReflex)
                        {
                            reflexVertices.Remove(vertex);
                        }
                    }
                }

                nVertices--;
                skipped = 0;
            }
            else if (++skipped > nVertices)
            {
                // If we have gone through all remaining vertices and not found ear, then fail.
                return(new int[] { });
            }

            current = next;
        }

        // Remaining polygon _is_ a triangle.
        triangles.Add(current.Prev.Index);
        triangles.Add(current.Index);
        triangles.Add(current.Next.Index);

        return(triangles);
    }
 private static bool IsReflex(bool isCcw, PolygonVertex v)
 {
     return(isCcw ? v.WindingValue <= 0.0f : v.WindingValue >= 0.0f);
 }
Beispiel #12
0
 public bool ContainsVertex(PolygonVertex v)
 {
     return(PolyVertexCache.ContainsKey(v));
 }