Beispiel #1
0
        /// <summary>
        /// Build new polygon from ellipse. The ellipse is
        /// defined by the specified bounding rectangle. The
        /// second parameter specifies how close the
        /// polygon approximates the ellipse.
        /// Factor of 0 specifies simplest polygon, while
        /// factor 100 specifies the most complex polygon.
        /// </summary>
        /// <param name="bounds"></param>
        /// <param name="factor"></param>
        public Polygon(RectangleF bounds, int factor)
        {
            if (factor < 0)
            {
                factor = 0;
            }
            if (factor > 100)
            {
                factor = 100;
            }

            GraphicsPath path = new GraphicsPath();

            path.AddEllipse(bounds);
            path.Flatten(new Matrix(), (float)factor / 100f);
            _points = new PointList(path.PathPoints);

            path.Dispose();

            Complete();
        }
Beispiel #2
0
        /// <summary>
        /// Creates single h-line at the specified vertical offset.
        /// </summary>
        private PointList BuildLine(float yOff)
        {
            PointF p11 = new PointF(_bounds.Left - 1, 0);
            PointF p12 = new PointF(_bounds.Right + 1, 0);
            PointF p21 = new PointF(_bounds.Left - 1, 0);
            PointF p22 = new PointF(_bounds.Right + 1, 0);

            p11.Y = p12.Y = yOff;
            yOff += _text.Height;
            if (yOff > _bounds.Bottom)
            {
                return(null);
            }
            p21.Y = p22.Y = yOff;

            ArrayList merge  = new ArrayList();
            PointList result = new PointList();
            PointList row1   = PolygonIntersect(p11, p12);
            PointList row2   = PolygonIntersect(p21, p22);

            int i;

            for (i = 0; i < row1.Count; i++)
            {
                merge.Add(new DirPt(row1[i], i % 2 == 1 ? 2 : 0));
            }
            for (i = 0; i < row2.Count; i++)
            {
                merge.Add(new DirPt(row2[i], i % 2 == 1 ? 3 : 1));
            }

            merge.Sort();

            PointF pt    = PointF.Empty;
            int    inter = -1;          // 0 - for first line, 2 for second line, 4 - for both

            for (i = 0; i < merge.Count; i++)
            {
                DirPt temp = merge[i] as DirPt;

                if (temp.Direction == 2 || temp.Direction == 3)                 // out
                {
                    if (inter != 4)
                    {
                        if (inter == 0 && temp.Direction == 2)
                        {
                            inter = -1;
                        }
                        else if (inter == 2 && temp.Direction == 3)
                        {
                            inter = -1;
                        }
                        continue;
                    }

                    pt.Y       = yOff - _text.Height;
                    temp.Point = new PointF(temp.Point.X, yOff);

                    // Make points relative to the upper-left point of the polygon
                    pt.X      -= _bounds.Left;
                    pt.Y      -= _bounds.Top;
                    temp.Point = new PointF(
                        temp.Point.X - _bounds.Left,
                        temp.Point.Y - _bounds.Top);

                    result.Add(pt);
                    result.Add(temp.Point);

                    if (temp.Direction == 2)
                    {
                        inter = 2;
                    }
                    else
                    {
                        inter = 0;
                    }
                }
                else
                {
                    pt = temp.Point;

                    if (temp.Direction == 0)
                    {
                        if (inter == -1)
                        {
                            inter = 0;
                        }
                        else if (inter == 2)
                        {
                            inter = 4;
                        }
                    }
                    else
                    {
                        if (inter == -1)
                        {
                            inter = 2;
                        }
                        else if (inter == 0)
                        {
                            inter = 4;
                        }
                    }
                }
            }

            // Check if the center point of each
            // rectangle lies within the polygon
            for (i = 0; i < result.Count;)
            {
                PointF pt1 = result[i];
                PointF pt2 = result[i + 1];
                PointF ptc = PointF.Empty;

                ptc.X = (pt1.X + pt2.X) / 2 + _bounds.Left;
                ptc.Y = (pt1.Y + pt2.Y) / 2 + _bounds.Top;

                if (!_polygon.Contains(ptc))
                {
                    result.RemoveAt(i);
                    result.RemoveAt(i);
                }
                else
                {
                    i += 2;
                }
            }

            return(result);
        }
Beispiel #3
0
        /// <summary>
        /// Draws a previously laid-out text at a specified offset.
        /// </summary>
        public void Draw(float xOff, float yOff,
                         RenderTextCallback renderCallback, DrawTextHint hint)
        {
            if (GetHLines(_totalLines) == null)
            {
                throw new Exception("Draw invoked on a non-laid-out text.");
            }
            if (GetHLines(_totalLines).Count == 0)
            {
                return;
            }

            bool styled = (_text is StyledText);

            bool is_LastWord = false;

            // Original brush and font
            System.Drawing.Brush brushOriginal = hint.Brush;
            Font fontOriginal = hint.Font;

            // We now have the starting line and the number
            // of total lines to layout the text in. Go for it
            int iword = 0;

            for (int i = _startLine; i < _startLine + _totalLines; i++)
            {
                PointList hLine = GetHLines(_totalLines)[i] as PointList;

                for (int j = 0; j < hLine.Count; j += 2)
                {
                    PointF     pt1 = hLine[j];
                    PointF     pt2 = hLine[j + 1];
                    RectangleF rc  = new RectangleF(
                        _bounds.X + xOff + pt1.X,
                        _bounds.Y + yOff + pt1.Y,
                        pt2.X - pt1.X, pt2.Y - pt1.Y);

                    bool newLine = false;
                    int  newword = FitTextInRect(iword, rc, ref newLine);

                    if (newword > iword)
                    {
                        // Calculate the total width of the words
                        // which are about to be rendered, but skip
                        // the whitespaces at the front and the rear
                        int ifront = iword;
                        int irear  = newword - 1;

                        /*DON'T SKIP WHITESPACES ( next 2 lines )
                         *
                         */

                        while (ifront < newword && _text.Words[ifront].IsWhitespace)
                        {
                            ifront++;
                        }
                        while (irear >= ifront && _text.Words[irear].IsWhitespace)
                        {
                            irear--;
                        }



                        int   w;
                        float total = 0;
                        for (w = ifront; w <= irear; w++)
                        {
                            total += _text.Words[w].Width;
                        }

                        // Adjust the left side of the destination
                        // rectangle according to the specified alignment
                        switch (_options.Alignment)
                        {
                        case StringAlignment.Near:
                            // Do nothing
                            break;

                        case StringAlignment.Center:
                            rc.X = rc.X + (rc.Width - total) / 2;
                            break;

                        case StringAlignment.Far:
                            rc.X = rc.Right - total;
                            break;
                        }

                        // Render the words in the range [ifront, irear]
                        for (w = ifront; w <= irear; w++)
                        {
                            Word word = _text.Words[w];

                            if (w == _text.Words.Count - 1)
                            {
                                is_LastWord = true;
                            }
                            else
                            {
                                is_LastWord = false;
                            }

                            if (!_fits && hint.AddEllipsis && styled)
                            {
                                if (i == _startLine + _totalLines - 1)
                                {
                                    if (j == hLine.Count - 2)
                                    {
                                        if (w == irear)
                                        {
                                            // Append the last word with ellipsis
                                            StyledText.StyledWord sword =
                                                word as StyledText.StyledWord;
                                            StyledText.StyledWord newWord = null;

                                            int   chars = sword.Value.Length;
                                            float width = sword.Width;
                                            do
                                            {
                                                newWord = new StyledText.StyledWord(
                                                    sword.Value.Substring(0, chars) + "...", sword.Format, sword.Color);
                                                newWord.UpdateMeasures(hint.Graphics, hint.Font);
                                                chars--;
                                            }while (chars > 0 && newWord.Width > width);

                                            word = newWord;
                                        }
                                    }
                                }
                            }

                            /*DON'T SKIP WHITESPACES ( next line )
                             *
                             */

                            if (!word.IsLineBreak && !word.IsWhitespace)


                            {
                                if (styled)
                                {
                                    // In case of styled text formatting,
                                    // apply fonts and colors
                                    StyledText.StyledWord sword =
                                        word as StyledText.StyledWord;

                                    hint.Font  = sword.CreateFont(hint.Font);
                                    hint.Brush = sword.CreateBrush(hint.Brush);

                                    rc.Y += sword.YOffset;
                                }

                                // Add 10 to width and height becaus GDI+ stupid
                                // and clips the text

                                hint.IsLastLine  = is_LastWord;
                                hint.CurrentWord = word;

                                renderCallback(word.Value, new RectangleF(
                                                   rc.X, rc.Y, word.Width + 10, rc.Height + 10), hint);

                                if (styled)
                                {
                                    // Restore font and brush
                                    StyledText.StyledWord sword =
                                        word as StyledText.StyledWord;

                                    sword.DisposeFont(hint.Font);
                                    sword.DisposeBrush(hint.Brush);
                                    hint.Font  = fontOriginal;
                                    hint.Brush = brushOriginal;

                                    rc.Y -= sword.YOffset;
                                }
                            }
                            rc.X += _text.Words[w].Width;
                        }

                        iword = newword;
                    }

                    if (newLine)
                    {
                        break;
                    }
                }
            }
        }
Beispiel #4
0
        private bool DoLayout(Text text, Polygon polygon, LayoutOptions options)
        {
            // Initialize internal variables
            _text    = text;
            _polygon = polygon;
            _options = options;
            _bounds  = _polygon.Bounds;

            _fits = false;

            // Build the h-lines according to the layout settings
            BuildLines();

            // Find out the starting line and the total number
            // of lines needed to layout the text.
            _totalLines = 1;
            _startLine  = FirstLine(_totalLines);
            if (GetHLines(_totalLines).Count == 0)
            {
                return(false);
            }

            do
            {
                // Check if the text fits within the h-lines
                // in the range [_startLine, _startLine + _totalLines)
                int       iword = 0;
                PointList hLine = null;

                for (int i = _startLine; i < _startLine + _totalLines; i++)
                {
                    hLine = GetHLines(_totalLines)[i] as PointList;
                    for (int j = 0; j < hLine.Count; j += 2)
                    {
                        PointF     pt1 = hLine[j];
                        PointF     pt2 = hLine[j + 1];
                        RectangleF rc  = new RectangleF(
                            pt1.X, pt1.Y, pt2.X - pt1.X, pt2.Y - pt1.Y);

                        bool newLine = false;
                        iword = FitTextInRect(iword, rc, ref newLine);

                        if (newLine)
                        {
                            break;
                        }
                        if (iword >= _text.Words.Count)
                        {
                            _fits = true;
                            return(true);
                        }
                    }
                }

                // If the text does not fit, increase the total
                // number of lines and recalculate the starting
                // line depending on v-alignment.
                _totalLines++;
                if (_totalLines > GetHLines(_totalLines).Count)
                {
                    _totalLines--;
                    return(false);
                }
                _startLine = FirstLine(_totalLines);

                ArrayList hLines = GetHLines(_totalLines);
                if (_startLine + _totalLines > hLines.Count)
                {
                    ArrayList hLines2 = GetHLines(_totalLines + 1);
                    if (_totalLines > hLines2.Count)
                    {
                        // The text would not fit in the
                        // polygon, so use all of the available
                        // space to layout as much text as possible
                        _totalLines = Math.Max(hLines.Count, hLines2.Count);
                        _startLine  = 0;
                        return(false);
                    }
                }
            }while ((_startLine = FirstLine(_totalLines)) != -1);

            return(false);
        }
Beispiel #5
0
		/// <summary>
		/// Finds a point inside the polygon.
		/// </summary>
		public PointF GetInternalPoint()
		{
			int cvi = FindConvexVertex();
			int prev = cvi > 0 ? cvi - 1 : _points.Count - 1;
			int next = (cvi + 1) % _points.Count;

			PointF v = _points[cvi];
			PointF a = _points[prev];
			PointF b = _points[next];

			PointList pl = new PointList();
			pl.Add(a); pl.Add(v); pl.Add(b);

			Polygon avb = new Polygon(pl);

			float minDist = float.MaxValue;
			PointF intPt = v;

			for (int i = 0; i < _points.Count; ++i)
			{
				if (i == cvi) continue;
				if (i == prev) continue;
				if (i == next) continue;

				PointF q = _points[i];
				if (avb.Contains(q))
				{
					float dist = (float)Math.Sqrt((q.X-v.X)*(q.X-v.X) + (q.Y-v.Y)*(q.Y-v.Y));
					if (dist < minDist)
					{
						minDist = dist;
						intPt = q;
					}
				}
			}

			if (intPt == v)
				return new PointF((a.X + b.X) / 2, (a.Y + b.Y) / 2);
			else
				return new PointF((v.X + intPt.X)/ 2, (v.Y + intPt.Y) / 2);
		}
Beispiel #6
0
		/// <summary>
		/// Calculates the intersections between the 
		/// polygon and the line defined by the given points.
		/// The result is a list containing all points of intersection.
		/// </summary>
		public PointList IntersectLine(PointF a, PointF b)
		{
			PointList result = new PointList();
			PointF point;

			for (int i = 0; i < _points.Count - 1; i++)
			{
				point = new Line(_points[i], _points[i + 1]).
					IntersectLine(a, b);

				if (!float.IsPositiveInfinity(point.X))
					result.Add(point);
			}

			return result;
		}
Beispiel #7
0
		/// <summary>
		/// Build new polygon from ellipse. The ellipse is
		/// defined by the specified bounding rectangle. The
		/// second parameter specifies how close the
		/// polygon approximates the ellipse.
		/// Factor of 0 specifies simplest polygon, while
		/// factor 100 specifies the most complex polygon.
		/// </summary>
		/// <param name="bounds"></param>
		/// <param name="factor"></param>
		public Polygon(RectangleF bounds, int factor)
		{
			if (factor < 0)
				factor = 0;
			if (factor > 100)
				factor = 100;

			GraphicsPath path = new GraphicsPath();

			path.AddEllipse(bounds);
			path.Flatten(new Matrix(), (float)factor / 100f);
			_points = new PointList(path.PathPoints);

			path.Dispose();

			Complete();
		}
Beispiel #8
0
		/// <summary>
		/// Builds new polygon object from the specified rectangle.
		/// </summary>
		/// <param name="rect"></param>
		public Polygon(RectangleF rect)
		{
			float l = Math.Min(rect.Left, rect.Right);
			float r = Math.Max(rect.Left, rect.Right);
			float t = Math.Min(rect.Top, rect.Bottom);
			float b = Math.Max(rect.Top, rect.Bottom);

			_points = new PointList(
				new PointF[]
				{
					new PointF(l, t),
					new PointF(r, t),
					new PointF(r, b),
					new PointF(l, b)
				});

			Complete();
		}
Beispiel #9
0
		/// <summary>
		/// Builds new polygon object from a given points list.
		/// </summary>
		public Polygon(PointList points)
		{
			if (points.Count < 3)
				throw new Exception("Polygons need at least 3 points.");

			_points = new PointList(points);

			Complete();
		}