|
-
Jan 18th, 2011, 08:02 AM
#1
Thread Starter
Lively Member
[RESOLVED] GDI warp path question
Hi,
I am rendering text by using the Paint event of the form and creating a path and filling it (i.e. in the normal way). I need to create this text effect:

Does anyone know how to warp the path to make it look like this? I've used warp + matrices in the past to create perspective style effects. I don't know how to do curvy warps though.
thanks
Paul
-
Jan 18th, 2011, 02:53 PM
#2
Re: GDI warp path question
I can't come up with a ready solution, but I'm interested in this topic and have some ideas about how it might be done. What I have in mind is to divide the rectangular box containing the original text path into narrow vertical slices and warp each rectangle to fit the upper and lower elliptical curves. I'll see if I can work something out, assuming nobody else replies with something more useful.
I have also noted several references on the web about fitting text to a Bezier curves which you might find interesting, although I think fitting the text to elliptical curves could be easier:
http://www.codeguru.com/cpp/g-m/gdi/...le.php/c10595/(in Csharp)
http://msdn.microsoft.com/en-us/magazine/dd263097.aspx(Petzold, in WPF)
http://www.planetclegg.com/projects/...ToSplines.html(in Java, I think).
BB
-
Jan 19th, 2011, 03:54 AM
#3
Thread Starter
Lively Member
Re: GDI warp path question
Great thanks. I was thinking of splitting the path into vertical sections too.
There's a version of Warp (for paths) which takes an array of points. I was thinking of calculating the array using a sine function. Going to investigate exactly how that version of warp works next.
Just can't help thinking there's a much easier way!
-
Jan 19th, 2011, 04:59 AM
#4
Re: GDI warp path question
On thinking about it, it might be better to split up the path letter by letter instead of into regular slices. It depends on the font you are using. It would be easy for a monospaced font, but otherwise you would have to measure the width of each letter (or maybe letter pair, to get the spacing right?). I would think of doing that with GraphicsPath.GetBounds for each letter (or pair), as it gives more accurate results than Graphics.MeasureString.
OK, suppose you get the rectangle bounding each letter (or each slice if you are doing it that way). You need to warp the corners to corresponding points along the elliptical arcs. Unfortunaly GDI+ doesn't help at with getting regularly spaced points along a curve. But it's not too difficult to calculate the position of points on an ellipse or elliptical arc. Basically:
Code:
x = a * Cos(theta)
y = b * Sin(theta)
where a and b are the axis lengths of the ellipse and theta is the angle on the surrounding circle. (At least, it's a lot easier than finding points along a Bezier curve!) You could map each pixel on the original rectanglar box to (say) 0.5 degrees in the formulas above and get a good perspective result. That's because an ellipse is basically a circle in perspective.
If you choose to divide the text into regular slices, it's very difficult to get a GraphicsPath corresponding to each slice. It would be easiest to convert the whole path to a Region and then slice it up, and transform each slice [EDIT: not sure how]; but the results may not look as good, among other reasons because GDI+ can't anti-alias the edges of a Region. I would look at the possibility of treating each slice as a clipping region, and use that somehow for drawing/filling slices of the GraphicsPath.
BB
Last edited by boops boops; Jan 19th, 2011 at 06:29 AM.
-
Jan 19th, 2011, 11:11 AM
#5
Re: GDI warp path question
Sorry, after all that, "calculating the array using a sine function" IS the right way to go. I tried transforming the PathPoints array of a text path with trig functions and after much tinkering got the following results:

It's the result of lots of scribbling diagrams on paper, half-remembered geometry and blind guesswork. So don't take the details too seriously, especially the trig code, as it may not work for text paths of different sizes. But it shows it can be done and it shouldn't take too much code. It's all on this form:
vb.net Code:
Imports System.Drawing.Drawing2D Public Class OldCurvedTextForm Private textPath As New GraphicsPath Private newPath As GraphicsPath Private textFont As Font = New Font("Georgia", 100, FontStyle.Regular, GraphicsUnit.Pixel) Private textString As String = "THIS IS MY STRING" Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint e.Graphics.SmoothingMode = SmoothingMode.HighQuality e.Graphics.DrawPath(Pens.Gray, textPath) e.Graphics.FillPath(Brushes.Yellow, newPath) e.Graphics.DrawPath(Pens.Black, newPath) End Sub Private Sub OldCurvedTextForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load textPath.AddString(textString, textFont.FontFamily, 0, 80, Point.Empty, Nothing) newPath = CurvePath(textPath) End Sub Private Function CurvePath(ByVal inputPath As GraphicsPath) As GraphicsPath Dim newPath As GraphicsPath Dim w = inputPath.GetBounds.Width / 2 Dim h = inputPath.GetBounds.Height / 2 Using mtx As New Matrix mtx.Translate(-w, -h) inputPath.Transform(mtx) End Using Dim newPathPoints(inputPath.PathPoints.Count - 1) As PointF For i As Integer = 0 To inputPath.PathPoints.Count - 1 Dim pf As PointF = inputPath.PathPoints(i) Dim newX = pf.X * Math.Cos(pf.X / w / 2) Dim newY = 2 * pf.Y / Math.Cos(pf.X / w) newPathPoints(i) = New PointF(newX, newY) Next newPath = New GraphicsPath(newPathPoints, inputPath.PathTypes) Using mtx As New Matrix mtx.Translate(w, h) inputPath.Transform(mtx) mtx.Translate(0, 5 * h) newPath.Transform(mtx) End Using Return newPath End Function End Class
BB
Last edited by boops boops; Jan 20th, 2011 at 03:19 AM.
Reason: code improvements, lines 34, 35 & 41
-
Jan 19th, 2011, 06:55 PM
#6
Thread Starter
Lively Member
Re: GDI warp path question
This is brilliant thanks!! I'd actually started to do exactly the same kind of function as you've done (transform path points with a sine function). You beat me to it though and ironed out a few of the issues I was having too, so thank you!!
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|