2.3 Text

2.3.1 Setting text size
2.3.2 Multiline text
2.3.3 Manipulating text
2.3.4 Text transformations
2.3.5 Alignment and justification
2.3.6 Text greeking
2.3.7 Using GD&T symbols

Like all other geometry, each text object is represented in the database by a key. Visualize has many different text attributes that are accessed through the key. Unlike other geometry, text attributes can be set at either the object or segment level. If any text attribute is set at both the segment level and on the TextKey, the TextKey setting takes precedence.

[snippet 2.3.a]
HPS::TextKit textKit;
textKit.SetPosition(Point(0, 0, 0));
textKit.SetFont("verdana");
textKit.SetText("TECH SOFT 3D");
textKit.SetColor(HPS::RGBColor(1, 0.5, 0));
textKit.SetAlignment(HPS::Text::Alignment::Center); // relative to insertion point
mySegmentKey.InsertText(textKit);
HPS.TextKit textKit = new HPS.TextKit();
textKit.SetPosition(new HPS.Point(0, 0, 0));
textKit.SetFont("verdana");
textKit.SetText("TECH SOFT 3D");
textKit.SetColor(new HPS.RGBAColor(1, 0.5f, 0));
textKit.SetSize(40, HPS.Text.SizeUnits.Pixels);
textKit.SetAlignment(HPS.Text.Alignment.Center); // aligns text horizontally relative to its insertion point
mySegmentKey.InsertText(textKit);
[figure 2.3.a] Text inserted at 40 pixels high

There is no limit to the length of text in a text object. In our C++ APIs, all string input is assumed to be UTF-8 encoded (for C#, simply use the String class). The UTF8 class can take any wide-character string and UTF-8 encode it. You can pass a UTF8 object to any function expecting a char const *. For most Western European languages, the ASCII character set matches the UTF-8 code points, so there is typically no need to encode these strings. To construct a UTF8 object, simply pass a character string to the constructor:

[snippet 2.3.b]
// normal ASCII
HPS::UTF8 myUTF8("TECH SOFT 3D");
// any wide-character string is legal
wchar_t const * someWideCharString = L"TECH SOFT 3D";
HPS::UTF8 myWideUTF8(someWideCharString);
UTF8 does not apply to C#. Simply use the 'String' object in its place.

Finding fonts

The font directory is where Visualize looks for installed fonts. On Windows platforms, this doesn't need to be adjusted unless your fonts are installed in a non-standard location. However, if necessary, this value can be set using HPS::World.SetFontDirectory(<font_path>). A list of directories can be specified using a semicolon-separated list.

You can also choose from a list of fonts that are available on the system. To do this from Visualize, you must perform a font search. Font searching is done using a HPS::WindowKey:

[snippet 2.3.c]
windowKey.FindFonts(fsr);
while (iter.IsValid()) {
HPS::FontInfoState state = iter.GetItem();
// get the name of the font
state.GetName();
iter.Next();
}
windowKey.FindFonts(out fsr);
HPS.FontSearchResultsIterator iter = fsr.GetIterator();
while (iter.IsValid())
{
HPS.FontInfoState state = iter.GetItem();
// get the name of the font
state.GetName();
iter.Next();
}

If no font is explicitly set, Visualize will use the default font, which is named "stroked". The font is programmatically rendered and thus there is no external font file. An example of that font can be found in the appendix. The "ts3d" font, also included with Visualize, additionally offers GD&T symbols.

2.3.1 Setting text size

Frequently, it is desirable for text size to adjust to different orientations or zoom levels, or to remain a fixed size while a scene is zoomed. Text size can be specified in several different units using HPS::TextKey::SetSize or HPS::TextAttributeControl::SetSize.

EnumerationDescription
HPS::Text::SizeUnits::ObjectSpace The number indicates text size in object space. This allows for fully transformable text, which is sized the same as most of the other geometries.
HPS::Text::SizeUnits::WorldSpace This number indicates the text size in world space. This is very similar to ObjectSpace except it includes any scales from any modelling matrices applied to the containing segment.
HPS::Text::SizeUnits::WindowRelative Text is sized relative to the size of the subwindow it inhabits
HPS::Text::SizeUnits::SubscreenRelative Text is sized relative to the size of the outer window
HPS::Text::SizeUnits::Pixels Text is sized in absolute pixels
HPS::Text::SizeUnits::Points Text is sized in points (see following notes about points)

Notes on specifying text in points

A point (not to be confused with a coordinate point) is a common text measurement approximately equal to 1/72 inch. When the text size is specified in points, the text will stay the same size, regardless of the size of the output window, and also regardless of the resolution of the display.

If your output display has a resolution of 72 pixels per inch, then a pixel is the same size as a point. If you have a 13-inch display, 72 pixels per inch corresponds roughly to a resolution of 640x480; on a 21-inch display, it corresponds roughly to a resolution of 1024x780.

For the text on the screen to be the right size when specified in points, Visualize has to know the size and resolution of your screen monitor. Visualize can find out the screen resolution, but there is no way for it to know how big your monitor is, so it guesses the monitor size assuming that a pixel is 1/72 inch (one point). If the monitor is a different size, or if the pixels are not square, you can use the HPS::WindowInfoControl to tell Visualize the actual size of the monitor.

[snippet 2.3.1.a]
unsigned int width, height;
myWindowKey.GetWindowInfoControl().ShowPhysicalPixels(width, height);
uint width, height;
myWindowKey.GetWindowInfoControl().ShowPhysicalPixels(out width, out height);

It is important to note that text specified in points can appear to be different sizes on different monitors. To render point-sized fonts in a scene, Visualize relies on the accuracy of the properties reported by machine-specific display hardware. As this can be inconsistent across a wide variety of machines, the rendered text size may vary across different hardware configurations. If you want consistent sizing across different display hardware, we recommend that you specify Pixels, SubscreenRelative, or WindowRelative font sizes.

Finally, if your output window contains Visualize subwindows, then it may be convenient to use HPS::TextKey::SetSize() to set the text size in window relative units (HPS::Text::SizeUnits::WindowRelative).

2.3.2 Multiline text

Multiline text is available by simply inserting a line break within the text string. The space between the lines can be controlled using HPS::TextKey::SetLineSpacing or HPS::TextAttributeControl::SetLineSpacing. The parameter you specify is simply a multiple of the default line spacing.

[snippet 2.3.2.a]
HPS::TextKey tk = mySegmentKey.InsertText(Point(0, 0, 0), "Good morning\nThis is another line");
tk.SetLineSpacing(2.0f); // doubles the default space between lines
tk.SetLineSpacing(0.5f); // halves the default space between lines
HPS.TextKey tk = mySegmentKey.InsertText(new HPS.Point(0, 0, 0), "Good morning\nThis is another line");
tk.SetLineSpacing(2.0f); // doubles the default space between lines
tk.SetLineSpacing(0.5f); // halves the default space between lines

2.3.3 Manipulating text

Like other geometry, text can be manipulated after insertion using the HPS::TextKey. Position, font, size, and color, among other attributes are available for modification. The text content itself can be accessed via HPS::TextKey::ShowText and can be modified using the various Edit functions. When editing text, the content is accessed and specified by row and column position.

[snippet 2.3.3.a]
HPS::TextKey textKey = mySegmentKey.InsertText(Point(0, 0, 0), "TECH SOFT 3D\nBUILD WITH THE BEST");
textKey.EditTextByDeletion(1, 6, 4); // modifying column 1, position 6, and deleting 4 chars
textKey.EditTextByInsertion(1, 6, 3, "FOR"); // inserting 3 chars into column 1, position 6
HPS.TextKey textKey = mySegmentKey.InsertText(new HPS.Point(0, 0, 0), "TECH SOFT 3D\nBUILD WITH THE BEST");
textKey.EditTextByDeletion(1, 6, 4); // modifying column 1, position 6, and deleting 4 chars
textKey.EditTextByInsertion(1, 6, 3, "FOR"); // inserting 3 chars into column 1, position 6
[figure 2.3.3.a] The original (left) and edited text (right)

Note that the row and column counts used as the parameters are offsets, hence the first column would be column zero. HPS::TextKey::EditTextByReplacement can also be used but it is a 1-to-1 operation and is therefore only useful if you're replacing a substring with string of equal length.

Computing text extent

Often, it is necessary to know in advance what size text is going to be drawn on the screen so that it can be positioned accurately within the scene, or so geometry can be properly drawn around the text. Visualize can compute text extents for you based on the font and window characteristics. Because the calculation relies on many top-level parameters (such as screen resolution), you need to use a HPS::KeyPath object, which builds a segment hierarchy from the text object to the top-level window. Information on using a key path can be found in this section.

The size of the text extents are returned as a fraction of the text's parent window (or subwindow).

[snippet 2.3.3.b]
float out_xfrac, out_yfrac;
myKeyPath.ComputeTextExtent("My text string....", out_xfrac, out_yfrac);
float out_xfrac, out_yfrac;
myKeyPath.ComputeTextExtent("My text string...", out out_xfrac, out out_yfrac);

Setting a text region

Computing the text extents returns the screen size of text, but it is sometimes desirable to do the opposite: to specify a screen-space extent that you want the text to be drawn within. This is useful when text needs to fit into a predefined area. In Visualize, this box is called a text region. Text regions are linear in shape, but text path, alignment, and rotation values will continue to be honored. For example, if you wanted to draw text between the points [-1, 0, 0] and [1, 0, 0], you could do something like this:

[snippet 2.3.3.c]
HPS::TextKey myTextKey = mySegmentKey.InsertText(Point(0, 0, 0), "This is my text!");
PointArray pointArray;
pointArray.push_back(Point(-1, 0, 0));
pointArray.push_back(Point(1, 0, 0));
bool fitting = true;
bool adjust_direction = true;
bool relative_coordinates = true;
bool window_space = false;
myTextKey.SetRegion(pointArray,
fitting,
adjust_direction,
relative_coordinates,
window_space);
[figure 2.3.3.b] In this example, the text is formatted to fit between the two points, marked by red dots.

To unset a text region, call the above method with zero points in the region argument.

2.3.4 Text transformations

When text is part of a scene, it is often necessary for the text to remain unaffected by the camera orientation so that text is always billboarded in the view. This billboarding effect is the Visualize default. To force text to obey modelling transformations, simply enable text transforms in the following way:

[snippet 2.3.4.a]
mySegmentKey.GetTextAttributeControl().SetTransform(HPS::Text::Transform::Transformable);
mySegmentKey.GetTextAttributeControl().SetTransform(HPS.Text.Transform.Transformable);

Visualize also provides two other types of text transforms that relate to individual characters within a text string. CharacterPositionOnly will enable transforms on the text's path but the orientation of individual characters remains unaffected.

[snippet 2.3.4.b]
mySegmentKey.GetTextAttributeControl().SetTransform(HPS::Text::Transform::CharacterPositionOnly);
mySegmentKey.GetTextAttributeControl().SetTransform(HPS.Text.Transform.CharacterPositionOnly);

2.3.5 Alignment and justification

Setting text alignment changes the position of the text relative to its insertion point. For example, when a text alignment of HPS::Text::Alignment::BottomLeft is used, the text is aligned such that the insertion point is at its bottom left.

[snippet 2.3.5.a]
mySegmentKey.GetTextAttributeControl().SetAlignment(HPS::Text::Alignment::BottomLeft);
mySegmentKey.InsertText(Point(0, 0, 0), "Tech Soft 3D");
mySegmentKey.GetTextAttributeControl().SetAlignment(HPS.Text.Alignment.BottomLeft);
mySegmentKey.InsertText(new HPS.Point(0, 0, 0), "Tech Soft 3D");
[figure 2.3.5.a] The text aligned with the insertion point at the bottom left. The red mark is the insertion point.

Justification controls how the lines of multiline text are displayed relative to other lines in the same text object. Remember that new lines are created through the use of '\n'.

[snippet 2.3.5.b]
mySegmentKey.GetTextAttributeControl().SetAlignment(HPS::Text::Alignment::Center,
mySegmentKey.InsertText(Point(0, 0, 0), "Choose\nTech Soft 3D\nfor high\nperformance\ngraphics");
mySegmentKey.GetTextAttributeControl().SetAlignment(HPS.Text.Alignment.Center,
HPS.Text.ReferenceFrame.WorldAligned,
HPS.Text.Justification.RightJustified);
mySegmentKey.InsertText(new HPS.Point(0, 0, 0), "Choose\nTech Soft 3D\nfor high\nperformance\ngraphics");
[figure 2.3.5.b] The text is right-justified with a center alignment.

Note the second parameter to HPS::TextKey::SetAlignment, HPS::Text::ReferenceFrame::WorldAligned. This parameter sets the orientation of the text region, and is particularly important when using rotated text. When using a WorldAligned orientation, the text region is aligned to the world coordinate system. When using a PathAligned orientation, the text region is oriented to the text's path (shown below, rotated 30 degrees). Note that when transforming text, the transform flag must be set to HPS::Text::Transform::Transformable.

[snippet 2.3.5.c]
HPS::TextKey textKey = mySegmentKey.InsertText(Point(0, 0, 0), "Choose\nTech Soft 3D\nfor high\nperformance\ngraphics");
mySegmentKey.GetTextAttributeControl().SetFont("stroked");
mySegmentKey.GetTextAttributeControl().SetSize(40, HPS::Text::SizeUnits::Points);
mySegmentKey.GetModellingMatrixControl().Rotate(0, 0, 30); // text rotated 30 degrees
mySegmentKey.GetTextAttributeControl().SetTransform(HPS::Text::Transform::Transformable);
HPS.TextKey textKey = mySegmentKey.InsertText(new HPS.Point(0, 0, 0), "Choose\nTech Soft 3D\nfor high\nperformance\ngraphics");
mySegmentKey.GetTextAttributeControl().SetFont("stroked");
mySegmentKey.GetTextAttributeControl().SetSize(40, HPS.Text.SizeUnits.Points);
mySegmentKey.GetModellingMatrixControl().Rotate(0, 0, 30); // text rotated 30 degrees
mySegmentKey.GetTextAttributeControl().SetTransform(HPS.Text.Transform.Transformable);
[figure 2.3.5.c] A rotated text block

It is also possible to rotate each text character instead of the whole block. To do this, you would replace the call to rotate the modelling matrix with:

[snippet 2.3.5.d]
mySegmentKey.GetTextAttributeControl().SetRotation(40);
mySegmentKey.GetTextAttributeControl().SetRotation(40);
[figure 2.3.5.d] A text block with rotated characters

Another possibility allows you to rotate the text path without rotating the characters. You can do this by assigning a path for the text to follow. However, in most cases, the desired effect is to have the characters rotate along with the entire text block. While you can do this using a modelling matrix rotation, this method is useful when you don't want the text to otherwise be affected by segment-level transformations.

[snippet 2.3.5.e]
// allows text to be "rotated" even when not transformable
mySegmentKey.GetTextAttributeControl().SetPath(Vector(1, 0.5f, 0));
// allows characters to be rotated with text block
mySegmentKey.GetTextAttributeControl().SetRotation(HPS::Text::Rotation::FollowPath);
// allows text to be "rotated" even when not transformable
mySegmentKey.GetTextAttributeControl().SetPath(new HPS.Vector(1, 0.5f, 0));
// allows characters to be rotated with text block
mySegmentKey.GetTextAttributeControl().SetRotation(HPS.Text.Rotation.FollowPath);

2.3.6 Text greeking

Text greeking is a rendering optimization that is useful when your scene contains a large amount of text. Text can be slow to render in some circumstances, and when text appears very small on the screen, the trade-off between rendering speed and usefulness is important to consider. Text greeking solves this problem by ignoring text that would be drawn below a certain arbitrary size. Alternatively, Visualize can draw a box or lines in place of the text so there is some indication that text is present, but simply too small to be drawn.

Since text is only subject to zoom when it is transformable, text transforms must be enabled in order for greeking to be useful. The code sample below will enable greeking for text sized below 6 points.

[snippet 2.3.6.a]
mySegmentKey.GetTextAttributeControl().SetTransform(HPS::Text::Transform::Transformable);
mySegmentKey.GetTextAttributeControl().SetGreeking(true, 6,
mySegmentKey.GetTextAttributeControl().SetTransform(HPS.Text.Transform.Transformable);
mySegmentKey.GetTextAttributeControl().SetGreeking(true, 6,
HPS.Text.GreekingUnits.Points, HPS.Text.GreekingMode.Box);

2.3.7 Using GD&T symbols

Geometry, Dimension & Tolerance [GD&T] symbols are used by the engineering industry to delineate geometric features that would be cumbersome to otherwise describe. Visualize supports the use of such symbols, provided you are using a font which defines them. The "ts3d" font, distributed with Visualize, is such a font. As the symbols are outside the ASCII character set, you must make sure they are UTF-8 encoded when inserting them. The HPS::UTF8 class is provided to facilitate the encoding. In C#, simply use the String object. The following code sample demonstrates how to do this:

[snippet 2.3.7.a]
wchar_t text[40];
wcscpy(text, L"TECH SOFT 3D ");
wchar_t gdt[] = { 0x2197, 0x2300, 0x21A7, 0 };
wcscat(text, gdt);
HPS::UTF8 gdt_str(text);
mySegmentKey.InsertText(Point(0, 0, 0), gdt_str);
mySegmentKey.GetTextAttributeControl().SetFont("ts3d");
String text = "TECH SOFT 3D\u2197\u2300\u21A7";
HPS.TextKey tk = mySegmentKey.InsertText(new HPS.Point(0, 0, 0), text);
mySegmentKey.GetTextAttributeControl().SetFont("ts3d");

For a list of all GD&T symbols, see the appendix.