|Title||Draw text that sits above or below a line segment in Visual Basic .NET|
|Description||This example shows how to draw text that sits above or below a line segment in Visual Basic .NET.
|Keywords||graphics, algorithms, fonts, rotated text, text on segment, line segment, Visual Basic .NET, VB.NET|
|Categories||Algorithms, Graphics, Graphics|
The key to this example is the DrawTextOnSegment method shown in the following code. It draws as many characters as will fit along a line segment.
' Draw some text along a line segment.
' Leave char_num pointing to the next character to be drawn.
' Leave start_point holding the coordinates of the last
' point used.
Private Sub DrawTextOnSegment(ByVal gr As Graphics, ByVal _
brush As Brush, ByVal font As Font, ByVal txt As String, _
ByRef first_ch As Integer, ByRef start_point As PointF, _
ByVal end_point As PointF, ByVal text_above_segment As _
Dim dx As Single = end_point.X - start_point.X
Dim dy As Single = end_point.Y - start_point.Y
Dim dist As Single = CSng(Math.Sqrt(dx * dx + dy * dy))
dx /= dist
dy /= dist
' See how many characters will fit.
Dim last_ch As Integer = first_ch
While (last_ch < txt.Length)
Dim test_string As String = txt.Substring(first_ch, _
last_ch - first_ch + 1)
If (gr.MeasureString(test_string, Font).Width > _
' This is one too many characters.
last_ch -= 1
last_ch += 1
If (last_ch < first_ch) Then Return
If (last_ch >= txt.Length) Then last_ch = txt.Length - 1
Dim chars_that_fit As String = txt.Substring(first_ch, _
last_ch - first_ch + 1)
' Rotate and translate to position the characters.
Dim state As GraphicsState = gr.Save()
If (text_above_segment) Then
-gr.MeasureString(chars_that_fit, font).Height, _
Dim angle As Single = CSng(180 * Math.Atan2(dy, dx) / _
gr.TranslateTransform(start_point.X, start_point.Y, _
' Draw the characters that fit.
gr.DrawString(chars_that_fit, font, brush, 0, 0)
' Restore the saved state.
' Update first_ch and start_point.
first_ch = last_ch + 1
Dim text_width As Single = _
start_point = New PointF( _
start_point.X + dx * text_width, _
start_point.Y + dy * text_width)
The code starts by getting a unit-length vector (cx, dy) pointing in the direction of the line segment. It then enters a loop making longer and longer strings until it finds one that won't fit on the line segment. It then removes the last character added giving the longest substring that will fit.
If the longest substring is empty, the method returns without drawing anything. If every character fits, the code sets the last character to be the final one in the string.
Next the code saves the Graphics object's state so the code can undo the transformations that follow.
If the method should draw the text above the line segment, the code adds a translation to the Graphics object to move the text up by the text's height.
The code then calculates the angle of the line segment and adds a rotation transformation to rotate the text to lie along the segment. It then adds a final translation to move the text to the segment's starting position.
Finally the code draws the text at the origin. The transformations rotate and position the text appropriately.
The code then cleans up. It restores the Graphics object's original state, sets first_ch to indicate the first character that didn't fit, and sets start_point to the last position drawn by the text.