Exemplo n.º 1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SplitEdgeResult"/> structure with the
        /// specified <see cref="SubdivisionEdge"/> instances.</summary>
        /// <param name="originEdge">
        /// The <see cref="SubdivisionEdge"/> with the same <see cref="SubdivisionEdge.Origin"/> as
        /// the instance that has been split.</param>
        /// <param name="destinationEdge">
        /// The <see cref="SubdivisionEdge"/> with the same <see
        /// cref="SubdivisionEdge.Destination"/> as the instance that has been split.</param>
        /// <param name="createdEdge">
        /// The <see cref="SubdivisionEdge"/> that has been newly created for one of the two parts
        /// resulting from the split, if any; otherwise, a null reference.</param>
        /// <param name="isEdgeDeleted">
        /// <c>true</c> if the <see cref="SubdivisionEdge"/> to be split has been deleted because
        /// both parts were duplicated by existing instances; otherwise, <c>false</c>.</param>

        public SplitEdgeResult(
            SubdivisionEdge originEdge, SubdivisionEdge destinationEdge,
            SubdivisionEdge createdEdge, bool isEdgeDeleted)
        {
            OriginEdge      = originEdge;
            DestinationEdge = destinationEdge;
            CreatedEdge     = createdEdge;
            IsEdgeDeleted   = isEdgeDeleted;
        }
Exemplo n.º 2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SubdivisionFace"/> class with the specified
        /// containing <see cref="Subdivision"/>, unique key, and outer and inner boundaries.
        /// </summary>
        /// <param name="owner">
        /// The <see cref="Subdivision"/> that contains the <see cref="SubdivisionFace"/>.</param>
        /// <param name="key">
        /// The unique key of the <see cref="SubdivisionFace"/> within its <paramref name="owner"/>.
        /// </param>
        /// <param name="outerEdge">
        /// A <see cref="SubdivisionEdge"/> on the outer boundary of the <see
        /// cref="SubdivisionFace"/>. This argument may be a null reference.</param>
        /// <param name="innerEdges">
        /// An <see cref="IEnumerable{T}"/> collection containing one <see cref="SubdivisionEdge"/>
        /// on each inner boundary of the <see cref="SubdivisionFace"/>. This argument may be a null
        /// reference.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="owner"/> is a null reference.</exception>
        /// <remarks>
        /// This constructor is intended for unit testing.</remarks>

        internal SubdivisionFace(Subdivision owner, int key,
                                 SubdivisionEdge outerEdge, IEnumerable <SubdivisionEdge> innerEdges) : this(owner, key)
        {
            _outerEdge = outerEdge;
            if (innerEdges != null)
            {
                _innerEdges = new ListEx <SubdivisionEdge>(innerEdges);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Adds the specified <see cref="SubdivisionEdge"/> to the <see cref="InnerEdges"/>
        /// collection.</summary>
        /// <param name="edge">
        /// The <see cref="SubdivisionEdge"/> to add.</param>
        /// <remarks>
        /// <b>AddInnerEdge</b> first creates a new collection that backs the <see
        /// cref="InnerEdges"/> property, if necessary.</remarks>

        internal void AddInnerEdge(SubdivisionEdge edge)
        {
            Debug.Assert(edge != null);

            if (_innerEdges == null)
            {
                _innerEdges = new ListEx <SubdivisionEdge>();
            }

            _innerEdges.Add(edge);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Updates the <see cref="SubdivisionFace"/> keys in the specified dictionaries after the
        /// specified <see cref="SubdivisionEdge"/> has been split.</summary>
        /// <param name="edge">
        /// The <see cref="SubdivisionEdge"/> whose splitting resulted in the current <see
        /// cref="SplitEdgeResult"/>.</param>
        /// <param name="edgeToFace1">
        /// An <see cref="Int32Dictionary{T}"/> that maps the keys of any existing half-edges to the
        /// keys of the incident bounded <see cref="Subdivision.Faces"/> of the corresponding <see
        /// cref="Subdivision.Edges"/> in a first <see cref="Subdivision"/>.</param>
        /// <param name="edgeToFace2">
        /// An <see cref="Int32Dictionary{T}"/> that maps the keys of any existing half-edges to the
        /// keys of the incident bounded <see cref="Subdivision.Faces"/> of the corresponding <see
        /// cref="Subdivision.Edges"/> in a second <see cref="Subdivision"/>.</param>
        /// <remarks>
        /// <b>UpdateFaces</b> ensures that the mapping between original and intersected faces
        /// established by the <see cref="Subdivision.Intersection"/> algorithm is kept up-to-date
        /// when edge splitting results in a valid <see cref="CreatedEdge"/>.</remarks>

        public void UpdateFaces(SubdivisionEdge edge,
                                Int32Dictionary <Int32> edgeToFace1, Int32Dictionary <Int32> edgeToFace2)
        {
            if (CreatedEdge == null)
            {
                return;
            }
            int face;

            if (edgeToFace1.TryGetValue(edge._key, out face))
            {
                Debug.Assert(face != 0);
                edgeToFace1.Add(CreatedEdge._key, face);
            }

            if (edgeToFace2.TryGetValue(edge._key, out face))
            {
                Debug.Assert(face != 0);
                edgeToFace2.Add(CreatedEdge._key, face);
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Moves the incident half-edge on one of the boundaries of the <see
        /// cref="SubdivisionFace"/> from the specified <see cref="SubdivisionEdge"/> to another
        /// specified instance.</summary>
        /// <param name="oldEdge">
        /// The incident <see cref="SubdivisionEdge"/> to replace with <paramref name="newEdge"/>.
        /// </param>
        /// <param name="newEdge">
        /// The incident <see cref="SubdivisionEdge"/> that replaces <paramref name="oldEdge"/>.
        /// </param>
        /// <returns>
        /// A <see cref="MoveEdgeResult"/> value indicating which <see cref="SubdivisionFace"/>
        /// properties were changed, if any.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="oldEdge"/> or <paramref name="newEdge"/> is a null reference.
        /// </exception>
        /// <remarks><para>
        /// If <see cref="OuterEdge"/> equals the specified <paramref name="oldEdge"/>,
        /// <b>MoveEdge</b> sets that property to the specified <paramref name="newEdge"/>.
        /// Otherwise, <b>MoveEdge</b> sets the first <see cref="InnerEdges"/> element that equals
        /// <paramref name="oldEdge"/> to <paramref name="newEdge"/>, if any.
        /// </para><para>
        /// Unlike the other <see cref="MoveEdge(SubdivisionEdge)"/> overload, this overload does
        /// not check the <see cref="SubdivisionEdge.Twin"/> of <paramref name="oldEdge"/>, nor
        /// remove single-edge cycles.</para></remarks>

        internal MoveEdgeResult MoveEdge(SubdivisionEdge oldEdge, SubdivisionEdge newEdge)
        {
            if (_outerEdge == oldEdge)
            {
                _outerEdge = newEdge;
                return(MoveEdgeResult.OuterChanged);
            }

            if (_innerEdges != null)
            {
                for (int i = 0; i < _innerEdges.Count; i++)
                {
                    if (_innerEdges[i] == oldEdge)
                    {
                        _innerEdges[i] = newEdge;
                        return(MoveEdgeResult.InnerChanged);
                    }
                }
            }

            return(MoveEdgeResult.Unchanged);
        }
Exemplo n.º 6
0
        /// <overloads>
        /// Moves the incident half-edge on one of the boundaries of the <see
        /// cref="SubdivisionFace"/>.</overloads>
        /// <summary>
        /// Moves the incident half-edge on one of the boundaries of the <see
        /// cref="SubdivisionFace"/> away from the specified <see cref="SubdivisionEdge"/>.
        /// </summary>
        /// <param name="oldEdge">
        /// The incident <see cref="SubdivisionEdge"/> to replace with another half-edge on the same
        /// boundary of the <see cref="SubdivisionFace"/>.</param>
        /// <returns>
        /// A <see cref="MoveEdgeResult"/> value indicating which <see cref="SubdivisionFace"/>
        /// properties were changed, if any.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="oldEdge"/> is a null reference.</exception>
        /// <remarks><para>
        /// If <see cref="OuterEdge"/> equals the specified <paramref name="oldEdge"/> or its twin,
        /// <b>MoveEdge</b> sets <see cref="OuterEdge"/> to the result of <see
        /// cref="SubdivisionEdge.GetOtherCycleEdge"/> for the specified <paramref name="oldEdge"/>.
        /// </para><para>
        /// Otherwise, <b>MoveEdge</b> searches for an <see cref="InnerEdges"/> element that equals
        /// <paramref name="oldEdge"/> or its twin. On success, <b>MoveEdge</b> removes that element
        /// if the cycle contains no other half-edges; otherwise, <b>MoveEdge</b> sets that element
        /// to the result of <see cref="SubdivisionEdge.GetOtherCycleEdge"/> for <paramref
        /// name="oldEdge"/>.</para></remarks>

        internal MoveEdgeResult MoveEdge(SubdivisionEdge oldEdge)
        {
            SubdivisionEdge oldTwin = oldEdge._twin;

            if (_outerEdge == oldEdge || _outerEdge == oldTwin)
            {
                _outerEdge = _outerEdge.GetOtherCycleEdge(oldEdge);
                Debug.Assert(_outerEdge != null);
                return(MoveEdgeResult.OuterChanged);
            }

            if (_innerEdges != null)
            {
                for (int i = 0; i < _innerEdges.Count; i++)
                {
                    SubdivisionEdge innerEdge = _innerEdges[i];
                    if (innerEdge == oldEdge || innerEdge == oldTwin)
                    {
                        if (oldEdge._next == oldTwin && oldEdge._previous == oldTwin)
                        {
                            _innerEdges.RemoveAt(i);
                            if (_innerEdges.Count == 0)
                            {
                                _innerEdges = null;
                            }
                            return(MoveEdgeResult.InnerRemoved);
                        }

                        _innerEdges[i] = innerEdge.GetOtherCycleEdge(oldEdge);
                        Debug.Assert(_innerEdges[i] != null);
                        return(MoveEdgeResult.InnerChanged);
                    }
                }
            }

            return(MoveEdgeResult.Unchanged);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SubdivisionElement"/> structure with the
        /// specified <see cref="SubdivisionEdge"/>.</summary>
        /// <param name="edge">
        /// The <see cref="SubdivisionEdge"/> stored in the <see cref="SubdivisionElement"/>.
        /// </param>
        /// <remarks>
        /// <see cref="ElementType"/> is set to <see cref="SubdivisionElementType.Edge"/>.</remarks>

        public SubdivisionElement(SubdivisionEdge edge)
        {
            ElementType = SubdivisionElementType.Edge;
            _value      = edge;
            _vertex     = PointD.Empty;
        }
Exemplo n.º 8
0
        /// <summary>
        /// Finds the half-edge bounding the <see cref="SubdivisionFace"/> that is nearest to and
        /// facing the specified coordinates.</summary>
        /// <param name="q">
        /// The <see cref="PointD"/> coordinates to locate.</param>
        /// <param name="distance">
        /// Returns the distance between <paramref name="q"/> and the returned <see
        /// cref="SubdivisionEdge"/>, if any; otherwise, <see cref="Double.MaxValue"/>.</param>
        /// <returns><para>
        /// The <see cref="SubdivisionEdge"/> on any outer or inner boundaries of the <see
        /// cref="SubdivisionFace"/> with the smallest distance to and facing <paramref name="q"/>.
        /// </para><para>-or-</para><para>
        /// A null reference if the <see cref="SubdivisionFace"/> is completely unbounded.
        /// </para></returns>
        /// <remarks><para>
        /// <b>FindNearestEdge</b> traverses the <see cref="OuterEdge"/> boundary and all <see
        /// cref="InnerEdges"/> boundaries, computing the distance from <paramref name="q"/> to each
        /// <see cref="SubdivisionEdge"/>. This is an O(n) operation where n is the number of
        /// half-edges incident on the <see cref="SubdivisionFace"/>.
        /// </para><para>
        /// If <paramref name="q"/> is nearest to an edge that belongs to a zero-area protrusion
        /// into the <see cref="SubdivisionFace"/>, <b>FindNearestEdge</b> returns the twin
        /// half-edge that faces <paramref name="q"/>, according to its <see
        /// cref="SubdivisionEdge.Face"/> orientation.</para></remarks>

        public SubdivisionEdge FindNearestEdge(PointD q, out double distance)
        {
            distance = Double.MaxValue;
            SubdivisionEdge nearestEdge = null;

            // find smallest distance to any outer cycle edge
            if (_outerEdge != null)
            {
                SubdivisionEdge edge = _outerEdge;
                do
                {
                    double d = edge.ToLine().DistanceSquared(q);
                    if (distance > d)
                    {
                        distance = d;
                        if (d == 0)
                        {
                            return(edge);
                        }
                        nearestEdge = edge;
                    }
                    edge = edge._next;
                } while (edge != _outerEdge);
            }

            // find smallest distance to any inner cycle edge
            if (_innerEdges != null)
            {
                for (int i = 0; i < _innerEdges.Count; i++)
                {
                    SubdivisionEdge innerEdge = _innerEdges[i];
                    SubdivisionEdge edge      = innerEdge;
                    do
                    {
                        double d = edge.ToLine().DistanceSquared(q);
                        if (distance > d)
                        {
                            distance = d;
                            if (d == 0)
                            {
                                return(edge);
                            }
                            nearestEdge = edge;
                        }
                        edge = edge._next;
                    } while (edge != innerEdge);
                }
            }

            if (nearestEdge == null)
            {
                return(null);
            }

            // check twin in case of zero-area protrusion
            if (nearestEdge._twin._face == this)
            {
                LineLocation location = nearestEdge.ToLine().Locate(q);
                if (location == LineLocation.Right)
                {
                    nearestEdge = nearestEdge._twin;
                }
            }

            distance = Math.Sqrt(distance);
            return(nearestEdge);
        }