Ejemplo n.º 1
0
        /// <summary>
        /// Determines the location of the specified <see cref="PointI"/> coordinates relative to
        /// the <see cref="LineI"/>, assuming they are collinear.</summary>
        /// <param name="q">
        /// The <see cref="PointI"/> coordinates to examine.</param>
        /// <returns>
        /// A <see cref="LineLocation"/> value indicating the location of <paramref name="q"/>
        /// relative to the <see cref="LineI"/>.</returns>
        /// <remarks>
        /// <b>LocateCollinear</b> is identical with <see cref="Locate"/> but assumes that <paramref
        /// name="q"/> is collinear with the <see cref="LineI"/>, and therefore never returns the
        /// values <see cref="LineLocation.Left"/> or <see cref="LineLocation.Right"/>.</remarks>

        public LineLocation LocateCollinear(PointI q)
        {
            int qx0 = q.X - Start.X, qy0 = q.Y - Start.Y;

            if (qx0 == 0 && qy0 == 0)
            {
                return(LineLocation.Start);
            }

            int qx1 = q.X - End.X, qy1 = q.Y - End.Y;

            if (qx1 == 0 && qy1 == 0)
            {
                return(LineLocation.End);
            }

            if (qx0 * qx1 <= 0 && qy0 * qy1 <= 0)
            {
                return(LineLocation.Between);
            }

            if ((End.X - Start.X) * qx0 < 0 || (End.Y - Start.Y) * qy0 < 0)
            {
                return(LineLocation.Before);
            }
            else
            {
                return(LineLocation.After);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Determines the squared distance between the <see cref="LineI"/> and the specified <see
        /// cref="PointI"/> coordinates.</summary>
        /// <param name="q">
        /// The <see cref="PointI"/> coordinates to examine.</param>
        /// <returns>
        /// The squared distance between <paramref name="q"/> and the <see cref="LineI"/>.</returns>
        /// <remarks>
        /// <b>DistanceSquared</b> returns either the squared length of the perpendicular dropped
        /// from <paramref name="q"/> on the <see cref="LineI"/>, or the squared distance between
        /// <paramref name="q"/> and <see cref="Start"/> or <see cref="End"/> if the perpendicular
        /// does not intersect the <see cref="LineI"/>.</remarks>

        public double DistanceSquared(PointI q)
        {
            if (q == Start || q == End)
            {
                return(0);
            }

            double x = Start.X, y = Start.Y;
            int    ax = End.X - Start.X, ay = End.Y - Start.Y;

            // set (x,y) to nearest LineI point from q
            if (ax != 0 || ay != 0)
            {
                double u = ((q.X - x) * ax + (q.Y - y) * ay) / (double)(ax * ax + ay * ay);
                if (u > 1)
                {
                    x = End.X; y = End.Y;
                }
                else if (u > 0)
                {
                    x += u * ax; y += u * ay;
                }
            }

            x = q.X - x; y = q.Y - y;
            return(x * x + y * y);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RectI"/> structure with the specified
        /// <see cref="PointI"/> coordinates and <see cref="SizeI"/> dimensions.</summary>
        /// <param name="location">
        /// The <see cref="Location"/> of the <see cref="RectI"/>.</param>
        /// <param name="size">
        /// The <see cref="Size"/> of the <see cref="RectI"/>.</param>

        public RectI(PointI location, SizeI size)
        {
            X      = location.X;
            Y      = location.Y;
            Width  = size.Width;
            Height = size.Height;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Finds the distance vector from the specified <see cref="PointI"/> coordinates to the
        /// nearest edges of the <see cref="RectI"/>.</summary>
        /// <param name="q">
        /// The <see cref="PointI"/> coordinates to examine.</param>
        /// <returns>
        /// A <see cref="PointI"/> vector indicating the distance of each <paramref name="q"/>
        /// coordinate from the nearest corresponding edge of the <see cref="RectI"/>.</returns>
        /// <remarks><para>
        /// <b>GetDistanceVector</b> defines the components of the returned <see cref="PointI"/>
        /// vector as follows, assuming that <em>qx</em> and <em>qy</em> are the coordinates of
        /// <paramref name="q"/>:
        /// </para><list type="table"><listheader>
        /// <term><b>X</b></term><term><b>Y</b></term><description>Condition</description>
        /// </listheader><item>
        /// <term>0</term><term></term><description>
        /// <see cref="Left"/> &lt;= <em>qx</em> &lt;= <see cref="Right"/></description>
        /// </item><item>
        /// <term><em>qx</em> – <see cref="Left"/></term><term></term>
        /// <description><em>qx</em> &lt; <see cref="Left"/></description>
        /// </item><item>
        /// <term><em>qx</em> – <see cref="Right"/></term><term></term>
        /// <description><em>qx</em> &gt; <see cref="Right"/></description>
        /// </item><item>
        /// <term/><term>0</term><description>
        /// <see cref="Top"/> &lt;= <em>qy</em> &lt;= <see cref="Bottom"/></description>
        /// </item><item>
        /// <term/><term><em>qy</em> – <see cref="Top"/></term>
        /// <description><em>qy</em> &lt; <see cref="Top"/></description>
        /// </item><item>
        /// <term/><term><em>qy</em> – <see cref="Bottom"/></term>
        /// <description><em>qy</em> &gt; <see cref="Bottom"/></description>
        /// </item></list><para>
        /// Each vector component is zero exactly if the corresponding <paramref name="q"/>
        /// coordinate lies within the corresponding <see cref="RectI"/> extension. Otherwise, the
        /// component’s absolute value indicates the coordinate’s distance from the nearest <see
        /// cref="RectI"/> edge, and its sign indicates that edge itself.</para></remarks>

        public PointI GetDistanceVector(PointI q)
        {
            int qx = q.X - X, qy = q.Y - Y;

            int x = (qx <0 ? qx : qx> Width ? qx - Width : 0);
            int y = (qy <0 ? qy : qy> Height ? qy - Height : 0);

            return(new PointI(x, y));
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Determines the location of the specified <see cref="PointI"/> coordinates relative to
        /// the <see cref="RectI"/>, including <see cref="Right"/> and <see cref="Bottom"/>.
        /// </summary>
        /// <param name="q">
        /// The <see cref="PointI"/> coordinates to examine.</param>
        /// <returns>
        /// A <see cref="RectLocation"/> value indicating the location of <paramref name="q"/>
        /// relative to the <see cref="RectI"/>.</returns>
        /// <remarks>
        /// <b>LocateClosed</b> is identical with <see cref="Locate"/> but assumes that the <see
        /// cref="RectI"/> contains the <see cref="Right"/> and <see cref="Bottom"/> coordinates,
        /// emulating <see cref="RectD"/> and <see cref="RectF"/> behavior.</remarks>

        public RectLocation LocateClosed(PointI q)
        {
            int qx = q.X - X, qy = q.Y - Y;

            RectLocation x = (qx < 0 ? RectLocation.BeforeX :
                              (qx == 0 ? RectLocation.StartX :
                               (qx < Width ? RectLocation.InsideX :
                                (qx == Width ? RectLocation.EndX : RectLocation.AfterX))));

            RectLocation y = (qy < 0 ? RectLocation.BeforeY :
                              (qy == 0 ? RectLocation.StartY :
                               (qy < Height ? RectLocation.InsideY :
                                (qy == Height ? RectLocation.EndY : RectLocation.AfterY))));

            return(x | y);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Determines the location of the specified <see cref="PointI"/> coordinates relative to
        /// the <see cref="LineI"/>.</summary>
        /// <param name="q">
        /// The <see cref="PointI"/> coordinates to examine.</param>
        /// <returns>
        /// A <see cref="LineLocation"/> value indicating the location of <paramref name="q"/>
        /// relative to the <see cref="LineI"/>.</returns>
        /// <remarks><para>
        /// <b>Locate</b> never returns <see cref="LineLocation.None"/>. The values <see
        /// cref="LineLocation.Left"/> and <see cref="LineLocation.Right"/> assume that
        /// y-coordinates increase upward.
        /// </para><para>
        /// <b>Locate</b> is based on the <c>classify</c> algorithm by Michael J. Laszlo,
        /// <em>Computational Geometry and Computer Graphics in C++</em>, Prentice Hall 1996, p.76.
        /// </para></remarks>

        public LineLocation Locate(PointI q)
        {
            int qx0 = q.X - Start.X, qy0 = q.Y - Start.Y;

            if (qx0 == 0 && qy0 == 0)
            {
                return(LineLocation.Start);
            }

            int qx1 = q.X - End.X, qy1 = q.Y - End.Y;

            if (qx1 == 0 && qy1 == 0)
            {
                return(LineLocation.End);
            }

            int ax = End.X - Start.X, ay = End.Y - Start.Y;
            int area = ax * qy0 - qx0 * ay;

            if (area > 0)
            {
                return(LineLocation.Left);
            }
            if (area < 0)
            {
                return(LineLocation.Right);
            }

            if (qx0 * qx1 <= 0 && qy0 * qy1 <= 0)
            {
                return(LineLocation.Between);
            }

            if (ax * qx0 < 0 || ay * qy0 < 0)
            {
                return(LineLocation.Before);
            }
            else
            {
                return(LineLocation.After);
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Finds the intersection between the <see cref="LineI"/> and the perpendicular dropped
        /// from the specified <see cref="PointI"/> coordinates.</summary>
        /// <param name="q">
        /// The <see cref="PointI"/> coordinates to examine.</param>
        /// <returns>
        /// The <see cref="PointD"/> coordinates where the perpendicular dropped from <paramref
        /// name="q"/> intersects the <see cref="LineI"/> or its infinite extension.</returns>
        /// <remarks>
        /// <b>Intersect</b> returns <see cref="Start"/> if <see cref="Length"/> equals zero.
        /// </remarks>

        public PointD Intersect(PointI q)
        {
            if (q == Start)
            {
                return(Start);
            }
            if (q == End)
            {
                return(End);
            }

            int x = Start.X, y = Start.Y;
            int ax = End.X - x, ay = End.Y - y;

            if (ax == 0 && ay == 0)
            {
                return(Start);
            }

            double u = ((q.X - x) * ax + (q.Y - y) * ay) / (double)(ax * ax + ay * ay);

            return(new PointD(x + u * ax, y + u * ay));
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Converts the specified <see cref="PointI"/> to a GDI <see cref="Point"/>.</summary>
        /// <param name="point">
        /// The <see cref="PointI"/> instance to convert.</param>
        /// <returns>
        /// A new GDI <see cref="Point"/> instance whose coordinates equal those of the specified
        /// <paramref name="point"/>.</returns>

        public static Point ToGdiPoint(this PointI point)
        {
            return(new Point(point.X, point.Y));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Initializes a new instance of the <see cref="LineI"/> structure with the specified start
        /// and end coordinates.</summary>
        /// <param name="start">
        /// The <see cref="Start"/> point of the <see cref="LineI"/>.</param>
        /// <param name="end">
        /// The <see cref="End"/> point of the <see cref="LineI"/>.</param>

        public LineI(PointI start, PointI end)
        {
            Start = start;
            End   = end;
        }
Ejemplo n.º 10
0
        /// <overloads>
        /// Initializes a new instance of the <see cref="LineI"/> structure.</overloads>
        /// <summary>
        /// Initializes a new instance of the <see cref="LineI"/> structure with the specified start
        /// and end coordinates.</summary>
        /// <param name="startX">
        /// The <see cref="PointI.X"/> coordinate of the <see cref="Start"/> point.</param>
        /// <param name="startY">
        /// The <see cref="PointI.Y"/> coordinate of the <see cref="Start"/> point.</param>
        /// <param name="endX">
        /// The <see cref="PointI.X"/> coordinate of the <see cref="End"/> point.</param>
        /// <param name="endY">
        /// The the <see cref="PointI.Y"/> coordinate of the <see cref="End"/> point.</param>

        public LineI(int startX, int startY, int endX, int endY)
        {
            Start = new PointI(startX, startY);
            End   = new PointI(endX, endY);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Moves the <see cref="RectI"/> by the specified <see cref="PointI"/> vector.</summary>
        /// <param name="vector">
        /// A <see cref="PointI"/> value whose components define the horizontal and vertical offset
        /// applied to the <see cref="RectI"/>.</param>
        /// <returns>
        /// A new <see cref="RectI"/> with the same <see cref="Size"/> as this instance, and whose
        /// <see cref="Location"/> is offset by the specified <paramref name="vector"/>.</returns>

        public RectI Offset(PointI vector)
        {
            return(new RectI(Location + vector, Size));
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Indicates whether the <see cref="RectI"/> contains the specified <see cref="PointI"/>
        /// coordinates, including <see cref="Right"/> and <see cref="Bottom"/>.</summary>
        /// <param name="point">
        /// The <see cref="PointI"/> to examine.</param>
        /// <returns>
        /// <c>true</c> if the <see cref="RectI"/> contains the specified <paramref name="point"/>,
        /// including <see cref="Right"/> and <see cref="Bottom"/>; otherwise, <c>false</c>.
        /// </returns>
        /// <remarks>
        /// <b>ContainsClosed</b> assumes that the <see cref="RectI"/> contains the <see
        /// cref="Right"/> and <see cref="Bottom"/> coordinates, emulating <see cref="RectD"/> and
        /// <see cref="RectF"/> behavior.</remarks>

        public bool ContainsClosed(PointI point)
        {
            return(ContainsClosed(point.X, point.Y));
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Indicates whether the <see cref="RectI"/> contains the specified <see cref="PointI"/>
        /// coordinates.</summary>
        /// <param name="point">
        /// The <see cref="PointI"/> to examine.</param>
        /// <returns>
        /// <c>true</c> if the <see cref="RectI"/> contains the specified <paramref name="point"/>;
        /// otherwise, <c>false</c>.</returns>
        /// <remarks>
        /// <b>Contains</b> assumes that the <see cref="RectI"/> does not contain the <see
        /// cref="Right"/> and <see cref="Bottom"/> coordinates.</remarks>

        public bool Contains(PointI point)
        {
            return(Contains(point.X, point.Y));
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Creates the regions of the Voronoi diagram.</summary>
        /// <remarks>
        /// <b>CreateRegions</b> stores its output in the <see cref="VoronoiRegions"/> property.
        /// Please see there for details.</remarks>

        private void CreateRegions()
        {
            /*
             * 1. Create list of unsorted edges for each region
             * ================================================
             * First we accumulate the raw material for each Voronoi region.
             * All edges are stored as indices into VoronoiVertices here.
             */

            var listRegions = new LinkedList <PointI> [GeneratorSites.Length];

            for (int i = 0; i < listRegions.Length; i++)
            {
                listRegions[i] = new LinkedList <PointI>();
            }

            foreach (VoronoiEdge edge in VoronoiEdges)
            {
                PointI vertex = new PointI(edge.Vertex1, edge.Vertex2);
                listRegions[edge.Site1].AddLast(vertex);
                listRegions[edge.Site2].AddLast(vertex);
            }

            /*
             * 2. Sort and complete list of edges for each region
             * ==================================================
             * Sort each edge list so that an edge’s second vertex index equals
             * the first vertex index of the subsequent edge in the region list.
             * We may need to swap an edge’s vertex indices to allow this connection.
             *
             * Because all Voronoi edges are terminated with a pseudo-vertex where they
             * intersect the clipping rectangle, a Voronoi region may appear as several
             * internally connected, but mutually disconnected series of edges. To get
             * a single connected list, we must then insert pseudo-edges that span either
             * a border or even a corner of the clipping rectangle.
             */

            for (int i = 0; i < listRegions.Length; i++)
            {
                var candidates = listRegions[i];
                var listRegion = new LinkedList <PointI>();

                // start with first unsorted edge
                listRegion.AddFirst(candidates.First.Value);
                candidates.RemoveFirst();

                var  candidate    = candidates.First;
                bool wasEdgeAdded = false;

                while (candidate != null)
                {
                    // save next candidate before removing current one
                    var nextCandidate = candidate.Next;

                    PointI vertex = candidate.Value;
                    for (var node = listRegion.First; node != null; node = node.Next)
                    {
                        Debug.Assert(vertex != node.Value); // all vertices are distinct

                        // invert edges with out-of-order indices
                        if (vertex.X == node.Value.X || vertex.Y == node.Value.Y)
                        {
                            vertex = new PointI(vertex.Y, vertex.X);
                        }

                        // move preceding edge to sorted list
                        if (vertex.Y == node.Value.X)
                        {
                            candidates.Remove(candidate);
                            listRegion.AddBefore(node, vertex);
                            wasEdgeAdded = true;
                            break;
                        }

                        // move succeeding edge to sorted list
                        if (node.Value.Y == vertex.X)
                        {
                            candidates.Remove(candidate);
                            listRegion.AddAfter(node, vertex);
                            wasEdgeAdded = true;
                            break;
                        }
                    }

                    // try next unsorted edge
                    candidate = nextCandidate;
                    if (candidate == null && candidates.Count > 0)
                    {
                        // connection across border or corner required
                        if (!wasEdgeAdded)
                        {
                            ConnectCandidates(candidates, listRegion);
                        }

                        // start over with first candidate node
                        candidate    = candidates.First;
                        wasEdgeAdded = false;
                    }
                }

                // replace unsorted with sorted list
                listRegions[i] = listRegion;
            }

            /*
             * 3. Transform index list into polygon for each region
             * ====================================================
             * We now have sorted lists containing all edges of each Voronoi region.
             * For closed (interior) regions, the last edge connects to the first,
             * and we store exactly one vertex per edge (we always choose the first).
             *
             * For open (exterior) regions, the first edge begins and the last edge ends
             * with two different pseudo-vertices. We must now close them in the same way
             * in which we connected separate sublists in step 2.
             *
             * That is, we add one or more pseudo-edges that connect the outer vertices
             * of the list across a border or corner of the clipping rectangle. Unlike
             * step 2, we may need to extend the connection across two corners.
             */

            _voronoiRegions = new PointD[GeneratorSites.Length][];

            for (int i = 0; i < listRegions.Length; i++)
            {
                LinkedList <PointI> listRegion = listRegions[i];

                int firstIndex = listRegion.First.Value.X;
                int lastIndex  = listRegion.Last.Value.Y;

                if (firstIndex != lastIndex)
                {
                    // extend region to last pseudo-vertex
                    listRegion.AddLast(new PointI(lastIndex, Int32.MinValue));

                    PointD firstVertex = GetVertex(firstIndex);
                    PointD lastVertex  = GetVertex(lastIndex);

                    // check if pseudo-vertices span one or two corners of clipping region
                    if (firstVertex.X != lastVertex.X && firstVertex.Y != lastVertex.Y)
                    {
                        CloseCornerRegion(listRegion, firstVertex, lastVertex);
                    }
                }

                PointD[] region = new PointD[listRegion.Count];
                _voronoiRegions[i] = region;

                // store coordinates for first vertex of each edge
                int j = 0;
                for (var edge = listRegion.First; edge != null; edge = edge.Next, j++)
                {
                    region[j] = GetVertex(edge.Value.X);
                }
            }
        }