示例#1
0
        /// <summary>Slices off anything below the given line.</summary>
        public override void SliceBottom(float sliceLine, VectorPath path)
        {
            float previous = Previous.Y;
            float current  = Y;

            // Both below?
            if (previous < sliceLine && current < sliceLine)
            {
                // Both below.
                path.RemoveVisually(this);

                return;
            }
            else if (previous >= sliceLine && current >= sliceLine)
            {
                // Do nothing.
                return;
            }

            // Split where the slice line is.
            VectorPoint newPoint = Split((sliceLine - previous) / (current - previous), path);

            // Delete the segment to the left/right.
            if (current < sliceLine)
            {
                // Delete this -> newPoint
                path.RemoveVisually(newPoint);
            }
            else
            {
                // Delete previous -> this
                path.RemoveVisually(this);
            }
        }
示例#2
0
        /// <summary>Gets the signed area of the "major" contour (the first one).
        /// It's signed as this can identify the winding order.</summary>
        public float GetSignedArea()
        {
            float sum = 0f;

            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                VectorPoint next = current.Next;

                if (next == null)
                {
                    // We're done!
                    break;
                }

                if (next.HasLine)
                {
                    sum += (next.Y + current.Y) * (next.X - current.X);
                }

                current = next;
            }

            return(sum / 2f);
        }
        /// <summary>Gets the nearest node in the given section of this shape to the given point.</summary>
        public VectorPoint Nearest(float x, float y, VectorPoint from, VectorPoint to)
        {
            VectorPoint nearest  = null;
            float       distance = float.MaxValue;

            // For each side, check if it is to the left of our point. if it is, flip contained.

            VectorPoint current = from;

            while (current != null)
            {
                float dx = current.X - x;
                float dy = current.Y - y;

                float dist = dx * dx + dy * dy;

                if (dist < distance)
                {
                    nearest  = current;
                    distance = dist;
                }

                if (current == to)
                {
                    // All done.
                    break;
                }

                current = current.Next;
            }

            return(nearest);
        }
        /// <summary>Finds all the separate contours in this path.</summary>
        public List <PathSegment> GetContours()
        {
            // All the first nodes of each contour:
            List <PathSegment> contours       = new List <PathSegment>();
            PathSegment        currentContour = null;

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

            while (current != null)
            {
                if (currentContour == null)
                {
                    // Create the contour:
                    currentContour = new PathSegment(current, this);
                }

                if (current.Next == null || !current.Next.HasLine)
                {
                    // Ensure it's closed:
                    current.IsClose = true;

                    currentContour.Last = current;
                    contours.Add(currentContour);
                    currentContour = null;
                }

                current = current.Next;
            }

            return(contours);
        }
        public int GetVertexCount(float accuracy)
        {
            int vertCount = 0;

            // Next, we must consider all extra points caused by curves:
            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                if (current.IsCurve)
                {
                    // It's a curve - get the line length:
                    VectorLine line = current as VectorLine;

                    float length = line.Length;

                    // And just add on extra points:
                    vertCount += (int)(length / accuracy);
                }

                if (!current.IsClose)
                {
                    vertCount++;
                }

                // Hop to the next one:
                current = current.Next;
            }

            return(vertCount);
        }
示例#6
0
        /// <summary>Recalculates the minimum values and width/height of this path, taking curves into account.</summary>
        public void RecalculateBounds()
        {
            if (FirstPathNode == null)
            {
                Width  = 0f;
                Height = 0f;
                MinY   = 0f;
                MinX   = 0f;

                return;
            }

            // Our temp boundaries:
            MinX = float.MaxValue;
            MinY = float.MaxValue;

            // We'll be using width/height temporarily as max:
            Width  = float.MinValue;
            Height = float.MinValue;

            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                // Recalc bounds:
                current.RecalculateBounds(this);

                // Hop to the next one:
                current = current.Next;
            }

            // Remove min values from width/height:
            Width  -= MinX;
            Height -= MinY;
        }
示例#7
0
        /// <summary>Removes this segment from the parent path.</summary>
        public void Remove()
        {
            // Get previous:
            VectorPoint previous = First.Previous;

            // Get next:
            VectorPoint next = Last.Next;

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

            if (next == null)
            {
                Path.LatestPathNode = previous;
            }
            else
            {
                next.Previous = previous;
            }
        }
示例#8
0
        /// <summary>Replaces this point with another.</summary>
        public void ReplaceWith(VectorPoint replacement, VectorPath path)
        {
            if (replacement == null)
            {
                return;
            }

            // Update next/prev:
            replacement.Next     = Next;
            replacement.Previous = Previous;
            replacement.IsClose  = IsClose;

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

            if (Previous == null)
            {
                path.FirstPathNode = replacement;
            }
            else
            {
                Previous.Next = replacement;
            }
        }
示例#9
0
        public void Transform(Matrix4x4 mat)
        {
            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                current.Transform(mat);
                current = current.Next;
            }
        }
示例#10
0
        /// <summary>"Simplifies" the curve values ensuring that it's possible to offset the parts of the path.
        /// Used by the path stroke system.</summary>
        public void SimplifyCurve()
        {
            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                if (current.IsCurve)
                {
                    CurveLinePoint clp = current as CurveLinePoint;

                    if (clp != null)
                    {
                        // Simplify:
                        clp.SimplifyCurve(this);
                    }
                    else
                    {
                        // Convert a QLP to a CLP:
                        QuadLinePoint qlp = current as QuadLinePoint;

                        if (qlp != null)
                        {
                            // Create but with both control points being the same:
                            clp           = new CurveLinePoint(qlp.X, qlp.Y);
                            clp.Control1X = qlp.Control1X;
                            clp.Control1Y = qlp.Control1Y;
                            clp.Control2X = qlp.Control1X;
                            clp.Control2Y = qlp.Control1Y;
                            clp.IsClose   = qlp.IsClose;

                            // Replace the node now:
                            if (qlp.Previous == null)
                            {
                                FirstPathNode = clp;
                            }
                            else
                            {
                                qlp.Previous.Next = clp;
                            }

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

                current = current.Next;
            }
        }
        /// <summary>Bounds the points in this path to being real workable numbers.
        /// NaN and infinities are eliminated.</summary>
        public void BoundToReal()
        {
            // Eliminate NaN/ infinities:
            VectorPoint point = FirstPathNode;

            while (point != null)
            {
                point.BoundToReal();
                point = point.Next;
            }
        }
示例#12
0
        /// <summary>Selects the point at the given index of this path.</summary>
        public VectorPoint SelectPoint(int index)
        {
            VectorPoint current = FirstPathNode;

            while (index != 0 && current != null)
            {
                index--;
                current = current.Next;
            }

            return(current);
        }
示例#13
0
        /// <summary>Multiply the normals of this path by the given value.</summary>
        public void MultiplyNormals(float by)
        {
            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                current.MultiplyNormals(by);

                // Hop to the next one:
                current = current.Next;
            }
        }
示例#14
0
        /// <summary>Sheers this path. Note that it's assumed to be at most 1 unit tall.</summary>
        public void Sheer(float by)
        {
            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                current.Sheer(by);

                // Hop to the next one:
                current = current.Next;
            }
        }
示例#15
0
        /// <summary>Advances this sampler by the given amount.</summary>
        public virtual void Advance(float by, bool readValue)
        {
            // Update the distance stepped:
            DistanceStepped += by;

            if (Current == null)
            {
                return;
            }

            bool changed = false;

            while (Current.Next != null)
            {
                // Get the current x point:
                float x = Current.Next.X;

                if (DistanceStepped < x)
                {
                    break;
                }

                // Hop to the next one:
                Current = Current.Next;

                changed = true;
            }

            if (readValue)
            {
                if (Current.Next == null)
                {
                    // Apply current - This is where clamp comes from:
                    CurrentValue = Current.Y;

                    return;
                }

                if (changed)
                {
                    Current.Next.SetupSampler(this);
                }

                // What's the difference between next and this?
                float deltaX = Current.Next.X - Current.X;

                // 0-1 progress factor:
                float progress = (DistanceStepped - Current.X) / deltaX;

                CurrentValue = Current.Next.SampleMapped(this, progress);
            }
        }
示例#16
0
        /// <summary>Extrudes this path along it's normals. Used to e.g. make something bold. Assumes one or more closed loops and that RecalculateNormals has been called.</summary>
        public void Extrude(float by)
        {
            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                // Pull it out:
                current.Extrude(by);

                // Hop to the next one:
                current = current.Next;
            }
        }
示例#17
0
        /// <summary>Copies a section of this path.
        /// Note that if p2 is before p1, it will safely loop over a closed node.
        /// </summary>
        public VectorPath CopySection(VectorPoint p1, float c1, VectorPoint p2, float c2)
        {
            // Split the line p1 at c1.
            // Split the line p2 at c2.
            // The section between these two nodes is the part we want.

            // Create the path:
            VectorPath path = new VectorPath();

            if (p1 == null)
            {
                p1 = FirstPathNode;
                c1 = 0f;
            }

            // Add the first node:
            path.AddPathNode(p1.PointAt(c1, true));

            VectorPoint current = p1.Next;

            while (current != p2 && current != null)
            {
                if (current == p1)
                {
                    // This occurs when p1 and p2 are not in the same shape.
                    throw new Exception("Section start and end are not from the same path.");
                }

                // Add a copy:
                path.AddPathNode(current.Copy());

                // Go to next:
                current = current.Next;

                if (current == null && p2 != null)
                {
                    // Need to loop back around unless p2 is null.
                    // Notice that we actively skip the moveTo itself as
                    // current is in the same location.
                    current = path.FirstPathNode.Next;
                }
            }

            if (current == p2 && p2 != null)
            {
                // Add it:
                path.AddPathNode(p2.PointAt(c2, false));
            }

            return(path);
        }
示例#18
0
        /// <summary>Recomputes path node count.</summary>
        public void CountNodes()
        {
            PathNodeCount = 0;

            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                // Add:
                PathNodeCount++;

                // Hop to the next one:
                current = current.Next;
            }
        }
示例#19
0
        public override string ToString()
        {
            string text = "";

            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                text += current.ToString() + "\r\n";

                // Hop to the next one:
                current = current.Next;
            }

            return(text);
        }
示例#20
0
        /// <summary>Scales this path by the given value.</summary>
        public void Move(float byX, float byY)
        {
            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                current.Move(byX, byY);

                // Hop to the next one:
                current = current.Next;
            }

            // Move bounds:
            MinX += byX;
            MinY += byY;
        }
示例#21
0
        /// <summary>Gets the signed area of the "major" contour (the first one).
        /// It's signed as this can identify the winding order.</summary>
        public float GetSignedArea()
        {
            float sum = 0f;

            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                if (current.HasLine)
                {
                    sum += current.SignedArea();
                }

                current = current.Next;
            }

            return(sum / 2f);
        }
示例#22
0
        /// <summary>Scales this path by the given value.</summary>
        public void Scale(float by)
        {
            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                current.Multiply(by);

                // Hop to the next one:
                current = current.Next;
            }

            // Scale the dimensions:
            MinX   *= by;
            MinY   *= by;
            Width  *= by;
            Height *= by;
        }
示例#23
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;
            }
        }
示例#24
0
        /// <summary>Resets the stepping through this sampler.</summary>
        public void Reset()
        {
            Current         = Path.FirstPathNode;
            DistanceStepped = 0f;

            // Write the value:
            if (Current != null)
            {
                CurrentValue = Current.Y;

                if (Current.Next != null)
                {
                    Current.Next.SetupSampler(this);
                }
            }
            else
            {
                CurrentValue = 0f;
            }
        }
示例#25
0
        /// <summary>Remove a point.
        /// Just directly removes the point from the linked list unlike RemoveVisually.</summary>
        public void Remove(VectorPoint point)
        {
            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;
            }
        }
示例#26
0
        /// <summary>Copies this vector path into the given one.</summary>
        public void CopyInto(VectorPath path)
        {
            VectorPoint point = FirstPathNode;

            while (point != null)
            {
                VectorPoint copiedPoint = point.Copy();

                path.AddPathNode(copiedPoint);

                // Copy close status:
                if (point.IsClose)
                {
                    copiedPoint.IsClose       = true;
                    path.CloseNode.ClosePoint = copiedPoint;
                }

                point = point.Next;
            }
        }
示例#27
0
        /// <summary>The length of this path.</summary>
        public float Length()
        {
            float length = 0f;

            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                if (current.HasLine)
                {
                    VectorLine line = current as VectorLine;

                    length += line.Length;
                }

                // Hop to the next one:
                current = current.Next;
            }

            return(length);
        }
示例#28
0
        /// <summary>Axis flip.</summary>
        public void Flip()
        {
            VectorPoint current = FirstPathNode;

            while (current != null)
            {
                current.Flip();

                // Hop to the next one:
                current = current.Next;
            }

            float x = Width;

            Width  = Height;
            Height = x;

            x    = MinX;
            MinX = MinY;
            MinY = x;
        }
示例#29
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;
            }
        }
        public VectorPoint GetShapeEnd()
        {
            if (Next == null)
            {
                return(this);
            }

            VectorPoint current = Next;

            while (current != null)
            {
                // Nothing after it or the next one is a moveto:
                if (current.Next == null || !current.Next.HasLine)
                {
                    return(current);
                }

                current = current.Next;
            }

            // This is actually unreachable:
            return(null);
        }
		/// <summary>Does the given section of this path contain the given point?</summary>
		public bool Contains(float x,float y,VectorPoint from,VectorPoint to){
			
			bool contained=false;
			
			// For each side, check if it is to the left of our point. if it is, flip contained.
			
			VectorPoint current=from;
			
			while(current!=null){
				
				VectorPoint pointB=(current==from)?to:current.Previous;
				
				// Figure out the bounding box of the line.
				// We're going to see if the point is outside it - if so, skip.
				
				float minX=(current.X<pointB.X)?current.X:pointB.X;
				
				// Point is to the left of tbe bounding box - ignore.
				if(minX>x){
					goto Next;
				}
				
				float maxX=(current.X>pointB.X)?current.X:pointB.X;
				
				// Point is to the right of this lines bounding box - ignore.
				// We do an inclusive ignore here as the line attached to this one might include it too.
				if(maxX<=x){
					goto Next;
				}
				
				float minY=(current.Y<pointB.Y)?current.Y:pointB.Y;
				
				// Point is below this lines bounding box - ignore.
				if(minY>y){
					goto Next;
				}
				
				// Special case if the point is above.
				float maxY=(current.Y>pointB.Y)?current.Y:pointB.Y;
				
				// We do an inclusive check here as the line attached to this one might include it too.
				if(maxY<=y){
					//The point is above for sure.
					contained=!contained;
					goto Next;
				}
				
				
				// It's sloping. What side of the line are we on? If we're on the right, the line is to the left.
				float gradient=(pointB.Y-current.Y)/(pointB.X-current.X);
				float c=current.Y-(gradient*current.X);
				
				// y<=mx+c means we're on the right, or on the line.
				if(((gradient*x)+c)<=y){
					contained=!contained;
				}
				
				if(current==to){
					// All done.
					break;
				}
				
				Next:
				current=current.Next;
				
			}
			
			return contained;
		}
		/// <summary>Gets the nearest node in the given section of this shape to the given point.</summary>
		public VectorPoint Nearest(float x,float y,VectorPoint from,VectorPoint to){
			
			VectorPoint nearest=null;
			float distance=float.MaxValue;
			
			// For each side, check if it is to the left of our point. if it is, flip contained.
			
			VectorPoint current=from;
			
			while(current!=null){
				
				float dx=current.X-x;
				float dy=current.Y-y;
				
				float dist=dx*dx + dy*dy;
				
				if(dist<distance){
					nearest=current;
					distance=dist;
				}
				
				if(current==to){
					// All done.
					break;
				}
				
				current=current.Next;
				
			}
			
			return nearest;
		}
//--------------------------------------