Example #1
0
        public override VectorPoint Copy()
        {
            MoveToPoint point = new MoveToPoint(X, Y);

            point.NormalX = NormalX;
            point.NormalY = NormalY;

            return(point);
        }
Example #2
0
        /// <summary>Moves the current pen location to the given point. Used when drawing paths.</summary>
        public void MoveTo(float x, float y)
        {
            // We need to add the first end:
            MoveToPoint point = new MoveToPoint(x, y);

            AddPathNode(point);

            CloseNode = point;
        }
Example #3
0
        /// <summary>Adds the given node to the start of the path. Must be a moveTo unless it's a temp thing.
        /// See AddPathNode to add to the end.</summary>
        public void AddPathNodeStart(VectorPoint point)
        {
            PathNodeCount++;

            if (FirstPathNode == null)
            {
                if (point.Unloaded)
                {
                    FirstPathNode = LatestPathNode = point;
                }
                else
                {
                    MoveToPoint move = point as MoveToPoint;

                    if (move == null)
                    {
                        // Add a blank MoveTo - this means that moveTo's are always the close nodes.
                        move          = new MoveToPoint(0f, 0f);
                        FirstPathNode = LatestPathNode = move;
                        CloseNode     = move;

                        PathNodeCount++;

                        point.Previous = move;
                        LatestPathNode = move.Next = point;
                    }
                    else
                    {
                        FirstPathNode = LatestPathNode = point;
                        CloseNode     = move;
                    }
                }
            }
            else
            {
                // Hook it onto the start:
                point.Previous         = null;
                point.Next             = FirstPathNode;
                FirstPathNode.Previous = point;
                FirstPathNode          = point;
            }
        }
Example #4
0
        /// <summary>Adds the given path onto the end of this one.</summary>
        public void Append(VectorPath path)
        {
            if (LatestPathNode == null)
            {
                // This path just becomes the same as the given one:
                FirstPathNode  = path.FirstPathNode;
                LatestPathNode = path.LatestPathNode;
                PathNodeCount  = path.PathNodeCount;
                CloseNode      = path.CloseNode;
            }
            else
            {
                // Add the first node:
                AddPathNode(path.FirstPathNode);
                LatestPathNode = path.LatestPathNode;

                // -1 because Add already added the first node.
                PathNodeCount += path.PathNodeCount - 1;

                CloseNode = path.CloseNode;
            }
        }
Example #5
0
        public override VectorPoint Copy()
        {
            MoveToPoint point = new MoveToPoint(X, Y);

            return(point);
        }
		/// <summary>Sorts this path such that any holes it contains begin closest to it's containing contour.
		/// This essentially allows paths with holes (think hole in o!) to be correctly triangulated.</summary>
		public void HoleSort(){
			
			// Already sorted?
			if(HoleSorted){
				return;
			}
			
			HoleSorted=true;
			
			if(FirstPathNode==null){
				return;
			}
			
			// Have we actually got any holes?
			// Look for a close node followed by a node contained within the previously closed shape.
			
			// All the first nodes of each contour:
			List<VectorPoint> firstNodes=new List<VectorPoint>(1);
			
			// Add the first one:
			firstNodes.Add(FirstPathNode);
			
			// Find all the contours:
			VectorPoint current=FirstPathNode.Next;
			
			while(current!=null){
				
				if(current.IsClose){
					
					if(current.Next!=null){
						// The following node is a new contour:
						firstNodes.Add(current.Next);
					}
					
				}
				
				current=current.Next;
			}
			
			// How many have we got?
			int contourCount=firstNodes.Count;
			
			// Next, for each contour, check if it is contained in any of the previous contours:
			for(int i=1;i<contourCount;i++){
				
				// Grab the node:
				VectorPoint node=firstNodes[i];
				
				// Get it's coords:
				float currentX=node.X;
				float currentY=node.Y;
				
				// Do any previous contours contain the first node?
				for(int c=i-1;c>=0;c--){
					
					// Get the shapes end node - thats the previous node of the following contour:
					VectorPoint shapeEnd=firstNodes[c+1].Previous;
					
					// Get the shapes start node:
					VectorPoint shapeStart=firstNodes[c];
					
					// Does this contour contain the current point?
					if(Contains(currentX,currentY,shapeStart,shapeEnd)){
						
						// Yep it does! We have a hole (or a fill inside a hole).
						// We're now going to shuffle it.
						// We need it to connect to the nearest node of it's containing contour.
						VectorPoint nearest=Nearest(currentX,currentY,shapeStart,shapeEnd);
						
						if(nearest!=shapeEnd){
							
							// Here comes the "sort" - it's a simple process;
							// Think of it as simply moving a virtual line which goes between the inner shape and the outer shape.
							
							// Get the last vert of this hole shape:
							VectorPoint lastOfShape;
							
							if(i==contourCount-1){
								lastOfShape=LatestPathNode;
							}else{
								lastOfShape=firstNodes[i+1].Previous;
							}
							
							// Clear close status - this will cause it to act as if there's two nodes on top of each other:
							lastOfShape.IsClose=false;
							
							// Get the one that comes after nearest:
							VectorPoint nearestNext=nearest.Next;
							
							// Get the following node:
							VectorPoint originalNext=lastOfShape.Next;
							
							// We're about to:
							// - Remove the shape from the set
							// - Add a new node to the end of the shape located at nearest.
							// - Insert the result between nearest and it's follower.
							
							// Pop the shape out:
							shapeEnd.Next=originalNext;
							
							if(originalNext==null){
								LatestPathNode=shapeEnd;
							}else{
								originalNext.Previous=shapeEnd;
							}
							
							// Duplicate nearest with a moveto node:
							MoveToPoint point=new MoveToPoint(nearest.X,nearest.Y);
							point.Previous=lastOfShape;
							point.Next=nearestNext;
							PathNodeCount++;
							
							if(nearestNext==null){
								LatestPathNode=point;
							}else{
								nearestNext.Previous=point;
							}
							
							// Add shape between nearest and it's duplicate.
							nearest.Next=node;
							node.Previous=nearest;
							lastOfShape.Next=point;
							
						}
						
						// This return isn't quite correct, but it's a safety measure.
						// It's because we may have further holes, but they will test if their inside this one.
						return;
						//break;
						
					}
					
				}
				
			}
			
		}
        /// <summary>Sorts this path such that any holes it contains begin closest to it's containing contour.
        /// This essentially allows paths with holes (think hole in o!) to be correctly triangulated.</summary>
        public void HoleSort()
        {
            // Already sorted?
            if (HoleSorted)
            {
                return;
            }

            HoleSorted = true;

            if (FirstPathNode == null)
            {
                return;
            }

            // Have we actually got any holes?
            // Look for a close node followed by a node contained within the previously closed shape.

            // All the first nodes of each contour:
            List <PathSegment> contours = GetContours();

            // How many have we got?
            int contourCount = contours.Count;

            // Next, for each contour, check if it is contained in any of the previous contours:
            for (int i = 0; i < contourCount; i++)
            {
                // Grab the contour:
                PathSegment contour = contours[i];

                // Get it's coords:
                float currentX = contour.First.X;
                float currentY = contour.First.Y;

                // Do any of the other contours contain the first node of this one?
                for (int c = 0; c < contourCount; c++)
                {
                    // Get the potential container contour:
                    PathSegment container = contours[c];

                    if (container == null || container == contour)
                    {
                        continue;
                    }

                    // Does this contour contain the current point?
                    if (container.Contains(currentX, currentY))
                    {
                        // Yep it does! We have a hole.
                        // No longer a valid contour:
                        contours[i] = null;

                        // We're now going to shuffle it.
                        // We need it to connect to the nearest node of it's containing contour.
                        // Think of it as simply moving a virtual line which goes between the inner shape and the outer shape.

                        // Get the nearest node:
                        VectorPoint nearest = container.Nearest(currentX, currentY);

                        while (!nearest.HasLine)
                        {
                            nearest = nearest.Next;
                        }

                        // Last is no longer a close.
                        // This will cause it to act as if there's two nodes on top of each other:
                        contour.Last.IsClose = false;

                        // We're about to:
                        // - Remove the shape from the set
                        // - Add a new node to the end of the shape located at nearest.
                        // - Insert the result between nearest and it's follower.

                        // Pop the shape out:
                        contour.Remove();

                        // Get current one after nearest:
                        VectorPoint nearestNext = nearest.Next;

                        // Add it back in at nearest.
                        // Duplicate nearest first - it'll be the "receiving" side:
                        MoveToPoint point = new MoveToPoint(nearest.X, nearest.Y);
                        point.Previous = contour.Last;
                        point.Next     = nearestNext;
                        PathNodeCount++;

                        if (nearestNext == null)
                        {
                            LatestPathNode = point;
                        }
                        else
                        {
                            nearestNext.Previous = point;
                        }

                        nearest.Next           = contour.First;
                        contour.First.Previous = nearest;
                        contour.Last.Next      = point;

                        // All done with this contour:
                        break;
                    }
                }
            }
        }
Example #8
0
        /// <summary>Remove a point and may insert a MoveTo
        /// to ensure the visual appearance of the rest of the path is unaffected.</summary>
        public void RemoveVisually(VectorPoint point)
        {
            // First, do the actual removal (inline version of Remove):
            if (point.Previous == null)
            {
                FirstPathNode = point.Next;
            }
            else
            {
                point.Previous.Next = point.Next;
            }

            if (point.Next == null)
            {
                LatestPathNode = point.Previous;
            }
            else
            {
                point.Next.Previous = point.Previous;
            }

            // If it's a MoveTo, do nothing else:
            if (point is MoveToPoint)
            {
                return;
            }

            // If the previous node is a MoveTo, move it to points location:
            VectorPoint previous = point.Previous;

            if (previous != null && (previous is MoveToPoint))
            {
                // Move that MoveTo to points location:
                previous.X = point.X;
                previous.Y = point.Y;
            }
            else
            {
                // Otherwise, create a MoveTo and insert where our point was.
                MoveToPoint moveTo = new MoveToPoint(point.X, point.Y);

                if (point.Previous == null)
                {
                    FirstPathNode = moveTo;
                }
                else
                {
                    moveTo.Previous     = point.Previous;
                    point.Previous.Next = moveTo;
                }

                if (point.Next == null)
                {
                    LatestPathNode = moveTo;
                }
                else
                {
                    moveTo.Next         = point.Next;
                    point.Next.Previous = moveTo;
                }
            }
        }
//--------------------------------------
//--------------------------------------
        /// <summary>Sorts this path such that any holes it contains begin closest to it's containing contour.
        /// This essentially allows paths with holes (think hole in o!) to be correctly triangulated.</summary>
        public void HoleSort()
        {
            // Already sorted?
            if (HoleSorted)
            {
                return;
            }

            HoleSorted = true;

            if (FirstPathNode == null)
            {
                return;
            }

            // Have we actually got any holes?
            // Look for a close node followed by a node contained within the previously closed shape.

            // All the first nodes of each contour:
            List <VectorPoint> firstNodes = new List <VectorPoint>(1);

            // Add the first one:
            firstNodes.Add(FirstPathNode);

            // Find all the contours:
            VectorPoint current = FirstPathNode.Next;

            while (current != null)
            {
                if (current.IsClose)
                {
                    if (current.Next != null)
                    {
                        // The following node is a new contour:
                        firstNodes.Add(current.Next);
                    }
                }

                current = current.Next;
            }

            // How many have we got?
            int contourCount = firstNodes.Count;

            // Next, for each contour, check if it is contained in any of the previous contours:
            for (int i = 1; i < contourCount; i++)
            {
                // Grab the node:
                VectorPoint node = firstNodes[i];

                // Get it's coords:
                float currentX = node.X;
                float currentY = node.Y;

                // Do any previous contours contain the first node?
                for (int c = i - 1; c >= 0; c--)
                {
                    // Get the shapes end node - thats the previous node of the following contour:
                    VectorPoint shapeEnd = firstNodes[c + 1].Previous;

                    // Get the shapes start node:
                    VectorPoint shapeStart = firstNodes[c];

                    // Does this contour contain the current point?
                    if (Contains(currentX, currentY, shapeStart, shapeEnd))
                    {
                        // Yep it does! We have a hole (or a fill inside a hole).
                        // We're now going to shuffle it.
                        // We need it to connect to the nearest node of it's containing contour.
                        VectorPoint nearest = Nearest(currentX, currentY, shapeStart, shapeEnd);

                        if (nearest != shapeEnd)
                        {
                            // Here comes the "sort" - it's a simple process;
                            // Think of it as simply moving a virtual line which goes between the inner shape and the outer shape.

                            // Get the last vert of this hole shape:
                            VectorPoint lastOfShape;

                            if (i == contourCount - 1)
                            {
                                lastOfShape = LatestPathNode;
                            }
                            else
                            {
                                lastOfShape = firstNodes[i + 1].Previous;
                            }

                            // Clear close status - this will cause it to act as if there's two nodes on top of each other:
                            lastOfShape.IsClose = false;

                            // Get the one that comes after nearest:
                            VectorPoint nearestNext = nearest.Next;

                            // Get the following node:
                            VectorPoint originalNext = lastOfShape.Next;

                            // We're about to:
                            // - Remove the shape from the set
                            // - Add a new node to the end of the shape located at nearest.
                            // - Insert the result between nearest and it's follower.

                            // Pop the shape out:
                            shapeEnd.Next = originalNext;

                            if (originalNext == null)
                            {
                                LatestPathNode = shapeEnd;
                            }
                            else
                            {
                                originalNext.Previous = shapeEnd;
                            }

                            // Duplicate nearest with a moveto node:
                            MoveToPoint point = new MoveToPoint(nearest.X, nearest.Y);
                            point.Previous = lastOfShape;
                            point.Next     = nearestNext;
                            PathNodeCount++;

                            if (nearestNext == null)
                            {
                                LatestPathNode = point;
                            }
                            else
                            {
                                nearestNext.Previous = point;
                            }

                            // Add shape between nearest and it's duplicate.
                            nearest.Next     = node;
                            node.Previous    = nearest;
                            lastOfShape.Next = point;
                        }

                        // This return isn't quite correct, but it's a safety measure.
                        // It's because we may have further holes, but they will test if their inside this one.
                        return;
                        //break;
                    }
                }
            }
        }
Example #12
0
        /// <summary>Converts this path to straight lines only.
        /// Accuracy is the approx average length of each line segment.</summary>
        public void ToStraightLines(float accuracy)
        {
            if (Width == 0f)
            {
                // Calc lengths etc:
                RecalculateBounds();
            }

            MoveToPoint prevMoveTo = null;
            VectorPoint point      = FirstPathNode;

            while (point != null)
            {
                // If it's straight/ a MoveTo, skip:
                if (point.IsCurve)
                {
                    VectorLine line = point as VectorLine;

                    // Replace it with n line segments:
                    int segmentCount = (int)(line.Length / accuracy);

                    if (segmentCount < 1)
                    {
                        segmentCount = 1;
                    }

                    // Setup:
                    float delta    = 1f / (float)segmentCount;
                    float progress = delta;

                    // Sample it segmentCount times:
                    VectorPoint previous = point.Previous;

                    for (int i = 0; i < segmentCount; i++)
                    {
                        float x;
                        float y;
                        line.SampleAt(progress, out x, out y);

                        // Create line segment:
                        StraightLinePoint slp = new StraightLinePoint(x, y);
                        slp.Previous = previous;

                        if (previous == null)
                        {
                            FirstPathNode = slp;
                        }
                        else
                        {
                            previous.Next = slp;
                        }

                        previous  = slp;
                        progress += delta;
                    }

                    // Increase node count:
                    PathNodeCount += segmentCount - 1;

                    // Link up after too:
                    if (point.Next == null)
                    {
                        LatestPathNode = previous;
                    }
                    else
                    {
                        point.Next.Previous = previous;
                    }

                    if (point.IsClose)
                    {
                        previous.IsClose = true;

                        if (prevMoveTo != null)
                        {
                            prevMoveTo.ClosePoint = previous;
                        }
                    }
                }
                else if (point is MoveToPoint)
                {
                    prevMoveTo = point as MoveToPoint;
                }

                // Next one:
                point = point.Next;
            }

            // Recalc:
            RecalculateBounds();
        }