====
Text
====

Text attributes are set using ``Set_Text_Font``, and allow a significant amount of control over how text is displayed. 


Text Size
=========

The most commonly used attribute is "size", which has a default of 0.03 screen relative units (sru). Thus, the size of the text is fixed relative to the size of the output window, or, more precisely (since text is measured by its height), the text size is fixed relative to the height of the output window. The size 0.03 sru specifies the text to be 3 percent of the height of the HOOPS output window on the screen. If the window is resized, the text will change in size to match. 

You can also specify the size of text in pixels. For example:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [set_text_font]
		   :end-before: //! [set_text_font] 

Text whose size is specified in pixels will not change in size when the output window is resized. You can specify size in pixels to keep small text readable, regardless of the resolution of the output display. 

It is often desirable to specify the size of text in points - for example:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [set_text_font_points]
		   :end-before: //! [set_text_font_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 640 by 480; on a 21-inch display, it corresponds roughly to a resolution of 1024 by 780. 

It is important to note that text specified in points can appear to be different sizes on different machines. To render point-sized fonts in a scene, HOOPS 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 pixel, sru or wru font sizes.

Finally, if your output window contains HOOPS subwindows (discussed :doc:`here </prog_guide/3dgs/03_4_viewing_windows>`), then it may be convenient to set the text size in window relative units (wru). 


Font Name
=========

A text size is often specified in combination with the font name. For example:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [set_font_by_name]
		   :end-before: //! [set_font_by_name] 

When you specify a font, HOOPS searches for the font among the generic fonts that are available on all systems.  If it is not among this group and the application is running on Microsoft Windows, HOOPS will look for the fonts listed in the registry.  An analogous search is performed on Mac OS X.  If the font is still not found and the system option "extended font search" is enabled, HOOPS will look for the font in the locations specified in the system option "font directory". You can set both of these options using ``Define_System_Options``.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [define_font_dir]
		   :end-before: //! [define_font_dir] 

You can specify a set of directories using a semicolon separated list.  If you have a specific font that your application installs and uses, we recommend specifying the location of this font via the  "font directory" system option. For instance, with your installation of HOOPS, you will find a top level directory named 'fonts'. In this location, there are a number of Kanji fonts and the ts3d font.  If your application needs to display Japanese characters, the Kanji fonts can be extremely useful.  The ts3d font that is shipped with HOOPS is a font that contains all the GD&T (Geometry, Dimension & Tolerance) symbols used in PMI (Product Manufacturing Information).  To make these fonts available, you can use the location of these fonts with the "font directory" option.

.. image:: images/bottle_pmi_with_ts3dfont.png

*An example of the ts3d font displaying PMI information.*

Valid choices for the font name can be found by performing a font search using ``Begin_Font_Search`` (refer to the HOOPS/3dGS Reference Manual for the syntax of how to use this command). Fonts fall into several classifications of font types. One of them is "stroked" which include HOOPS/3dGS built-in fonts that are drawn as polylines. HOOPS/3dGS also supports system fonts (such as GDI fonts under Windows platforms, and X11 fonts under Unix systems), as well as platform-independent TrueType fonts. For example, if ``Begin_Font_Search`` indicated that a font called *arial.ttf* was available, you could set:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [more_set_text_font]
		   :end-before: //! [more_set_text_font] 
 
Typically, you application startup code would perform a font search to identify available fonts, choose a default font to use for any text that the user inserts, and perhaps provide a font-chooser dialog to allow them to select one of the available fonts. 

If the requested font is not available on the system, HOOPS will fallback to a stroked font. A "fallback font" option for ``Set_Driver_Options`` allows the user to provide a list of fonts to compensate for the case when HOOPS cannot use the specified font. HOOPS Visualize will use the fallback font list before using the built-in stroked font. 

The *allfonts.c* program demonstrates how to use a font search to identify and display all the fonts available on the system, and provides information about each font using ``Show_Font_Info``.


Transforms
==========

Annotation Text
---------------

You can choose whether text is treated as annotation or as a part of the scene. Annotation text provides information about a scene, but is not part of the scene, such as a label "origin" at coordinates (0, 0, 0). Numbers on the face of a clock, or "flying logos", are examples of text that is part of a scene. 

By default, text is treated as annotation: It is drawn in screen space, oriented to face the camera, horizontal, and upright. Text size and orientation are not affected by any transformations in the scene; only the position of the text is transformed. As you rotate and move a scene, annotation text will continue to face you and will remain fixed in size. The attribute that controls this behavior is called "transforms", which are turned off by default, thus causing the text to be drawn in screen space.


Scene Text
----------

You can also treat text as part of a scene by using the "transforms" suboption of ``Set_Text_Font``. The transforms flag has four possible states: off (the default), on, character position only and character position adjusted.


The "on" state is the simplest option. HOOPS will assume that your text is aligned upright along the X-axis. When the camera rotates around, the text will appear as if it is lying on the X-Y plane. 

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [enable_font_transforms]
		   :end-before: //! [enable_font_transforms] 
		   
.. image:: images/02432a_TextTransformsOn.png

*An example of the text that has transforms set to on.*

For a more sophisticated treatment of scene text, HOOPS offers the character position only and character position adjusted options. For both of these options, HOOPS can render text such that it is aligned along a specified path. The text is also always screen facing. The following is sample code that shows how to set up this feature:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [set_text_path_alignment]
		   :end-before: //! [set_text_path_alignment] 

In the sample above, we first call ``Set_Text_Path`` which specifies a vector direction for your text.  In the next call, we set the text alignment to help HOOPS determine how to calculate the text bounding box. This text bounding box is an important part of the subsequent transformation calculation.  In this case, since we specified a path, the call to ``Set_Text_Alignment`` passes the "*" option which instructs HOOPS to refit the text box to a rotated string, aligning the borders of the box with the path of the text. Then a call to ``Set_Text_Font`` sets two options. The first option is "rotation". Setting the rotation to "follow path" path ensures that the text follows the specified path during transformation. As a result, the text orientation remains perpendicular to the vector direction. Finally, the transforms option is set to "character position only".


.. csv-table::

	.. image:: images/02432b_TransformCharPosOnlyPath.png, .. image:: images/02432b_TransformOnPath.png


*The left image shows text rendered with transforms set to "character position only" which displays the text screen facing no matter how the camera is positioned. While the right image shows the same text with the same camera position rendered with transforms set to "on".*

In the "character position only" option, there will be some cases where the text will appear upside down due to the camera position. If you want your text to appear right side up regardless of the camera position, then set the transforms option to "character position adjusted". This will tell HOOPS to detect when a transformation causes text to be turned upside down. At this point, HOOPS will simply flip the text. Note that this only works if you have set your text alignment to one of the "." variations as seen the code above. If you have not, the behavior will be as if you have transforms set to "character position only".

.. csv-table::

	.. image:: images/02432c_TextTransformsNoFlip.png, .. image:: images/02432c_TextTransformsFlip.png
	

*The left image shows text, rendered with transforms set to "character position only", appearing upside down due to the position of the camera.  While the right image shows text, rendered with transforms set to "character position adjusted", appearing right side up because it has been flipped by HOOPS.*
  
If you enable transforms for the text in your scene, you probably want to have the text size be in the same units of measurement as the rest of your scene. In this case, you should use object relative units (oru). For example, the following command sets the text to be 0.1 units high: 

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [set_text_transforms_size]
		   :end-before: //! [set_text_transforms_size]
		   
How big 0.1 oru turns out to be on the screen depends on the camera and on any local transformations in the scene. With the default camera and transformations, the HOOPS output window goes from -1.0 to 1.0 in width and height, so text 0.1 oru high at the origin will be one-twentieth of the height of the output window, which is equal to 0.05 sru. Like text specified in sru but unlike text specified in points or pixels, text specified in oru will change size as the size of the output window changes. Transformable text specified in oru will also change size as it gets closer to or farther away from the camera (assuming a perspective projection). 


Other Text Attributes
=====================

Alignment
---------

By default, text is aligned centered about its insertion point, so the command  

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [insert_text]
		   :end-before: //! [insert_text]
		   
will place the word "origin" right in the middle of the output window. You can change the alignment of text with ``Set_Text_Alignment``. For example, to left justify text, you can use

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [set_text_alignment_justify]
		   :end-before: //! [set_text_alignment_justify]
		   
You can change the vertical alignment of text with the same HOOPS command. The default is to center the text vertically. To align text to the baseline of the text (the bottom of the capital letters), you can specify 

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [set_text_alignment_baseline]
		   :end-before: //! [set_text_alignment_baseline]

The "v" is supposed to look like a down-pointing arrow. You can specify a vertical and horizontal alignment in the same command. For more information and other options, see the HOOPS Reference Manual entry for ``Set_Text_Alignment``. 


Text Greeking
-------------

Text greeking involves drawing a simple box at the text location if the text is going to be rendered below a certain size. The greeking limit is controlled using the ``Set_Text_Font`` option called "greeking limit", which sets the minimum text size for which a rectangular symbol will be substituted. For example:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [set_greeking]
		   :end-before: //! [set_greeking]
		   

Multiline Text
--------------

Text can be inserted in a multiline format (sometimes referred to as block text) by using a return character in the text string. Line spacing is controlled using the ``Set_Text_Font`` option called "line spacing". This is a floating point value which is multiplied by the current size of the text font. For example:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [line_spacing]
		   :end-before: //! [line_spacing]


Per-Character Attributes
------------------------

Per-character attributes are supported, and are set by calling ``MSet_Character_Attributes``.


Text Preference
---------------

The "preference" option of ``Set_Text_Font`` tells HOOPS which version of a font type to use at various font sizes. Using this interface allows the user to select raster, vector or exterior font rendering based on the screen size of the font. This can prove useful in a number of ways.  For instance, HOOPS only caches 'accurate' bitmaps up to a certain size, after which the largest bitmap is simply scaled.  The result of a high zoom factor is this situation would be a blurry or blocky text string. Consequently, you can instruct HOOPS to switch from 'vector' to 'raster' when fonts are beyond a certain size can help ensure that text still looks reasonable. In another case, when zooming, text might be illegible because characters were not rendered completely due to a number of font characteristics including the weight. To ensure that text is always rendered regardless of the size, select the 'exterior' option.  This tells HOOPS to render the polyline outline of each character of your text.


Text Rendering
--------------

The "renderer" option of ``Set_Text_Font`` allows the user to specify which HOOPS font-handling subsystem should be used to locate the specified font and make it available to HOOPS. Refer ``Set_Text_Font`` for more information. 


Other Custom Attributes
-----------------------

"Rotation", "slant", "size tolerance", and "extra space" are less commonly used attributes that allow you to further customize the appearance of text. See the ``Set_Text_Font`` command in the HOOPS/3dGS Reference Manual for details.


Manipulating Text
=================

Text can be manipulated with the following functions:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [manipulating_text]
		   :end-before: //! [manipulating_text] 
		   
 
Text as Geometry
================

You can convert text characters into other HOOPS geometry, such as shells. This involves checking if a font has an outline representation using ``Show_Font_Info``:
 
.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [text_as_geometry]
		   :end-before: //! [text_as_geometry] 


If the font is outlineable, then ``Compute_Text_Outline`` can be used to obtain the outlines for a text string. These outlines are in the format required by the 'shell' primitive (discussed in the :doc:`section about shells <02_8_geometry_shells>`). Note that we first need to call ``Compute_Text_Outline_Size`` to figure out how much space we need to store the outlines::

	char  *message = cool;
	int   pcount;
	Point *points;
	int   flist_length;
	int   *face_list;
	 
	HC_Open_Segment ("?picture"); 
		/* Find out how much space we'll need */ 
		HC_Compute_Text_Outline_Size (".", message, &pcount, &flist_length); 

		if (pcount <= 0) 
		 HC_Exit_Program (); 
		 
		/* Get some arrays to hold the glyphs' geometric data */ 
		face_list = (int *)malloc (flist_length * sizeof (int)); 
		points = (Point *)malloc (pcount * sizeof (Point)); 

		/* Get that geometric data for some text string */ 
		HC_Compute_Text_Outline (".", message, &pcount, &points[0], &flist_length, &face_list[0]); 

		/* insert a HOOPS shell primitive using the face_list information */
		HC_Insert_Shell(...);
	HC_Close_Segment();     


For complete examples of how to convert text into geometry, see the demo program *flylogo.c* located at *documentation/prog_guide/3dgs/examples/flylogo.c* in your HOOPS 3DF installation folder.


Calculating Text Extent
=======================

It is frequently necessary to know in advance what size text is going to be on the screen so that it can be positioned accurately within the scene, or so that a box can be properly drawn around the piece of text. The function ``Compute_Text_Extent`` calculates the screen extents of text. It returns the size in window coordinates as discussed in :doc:`the viewing section <03_1_viewing_modelling_coord_systems>`.

Prior to HOOPS version 16.0, the values returned by ``Compute_Text_Extent`` contained a small amount of white space around it.  Now, the default behavior for ``Compute_Text_Extent`` returns the exact extent for the specified text.  To revert to the behavior displayed by ``Compute_Text_Extent`` prior to 16.0, you can turn on the "legacy text extent" option in ``Define_System_Options``.


Setting a Text Region
=====================

The ``Compute_Text_Extent`` function can return 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 at. This is sometimes referred to as text billboarding, and can be useful when text needs to fit into a predefined width or box, etc... You can specify the extents of text by calling ``Set_Text_Region``. This applies an attribute to a specific piece of text, thus the text primitive must first be opened by calling ``Open_Geometry``::

	HC_Open_Geometry(text_key);    
	  HC_Set_Text_Region(...);
	HC_Close_Geometry();


Text Region Options
-------------------

``Set_Text_Region`` provides a variety of options to control the layout of the text region.


Inserting Text With Encoding
============================

HOOPS/3dGS supports the Unicode standard which enables internationalization of HOOPS-based applications that contain text in the HOOPS/3dGS database. To insert Unicode text into the HOOPS/3dGS database, use ``Insert_Text_With_Encoding``. This function takes as one if its parameters an encoding. For Unicode strings, HOOPS/3dGS support UTF-8, UTF-16 and UTF-32 which are indicated by passing "utf8", "utf16" or "utf32" respectively to ``Insert_Text_With_Encoding``. The following code sample shows how you can insert a UTF-16 encoded string:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [insert_text_with_encoding]
		   :end-before: //! [insert_text_with_encoding] 

When you are inserting text into the the HOOPS/3dGS database programmatically as opposed to loading it from a file, you might not know what type of encoding is being used.  For this case, if your text comes in the form of ``wchar_t`` array, you can still use ``Insert_Text_With_Encoding``. When you call the function, pass the ``wchar_t`` array and set the encoding parameter to "wcs". HOOPS will determine automatically what type of encoding is being used as seen in the code sample below:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../../demo/common/sanity/0700_docs_0009.cpp
		   :start-after: //! [insert_unicode_text]
		   :end-before: //! [insert_unicode_text] 
		   
For applications that run on systems with an Asian locale, Asian characters are legal and appear accurately throughout the system. However, Asian characters may not be rendered accurately in HOOPS unless they are inserted using ``Insert_Text_With_Encoding``. When you call the function and pass a string that may contain Asian characters, be sure to pass "mbs" for encoding thus indicating that this is a multi-byte string.

Note that the font set in ::Set_Text_Font should contain the character you specify. For more information about the Unicode standard, visit www.unicode.org.


Inserting GD&T Symbols
----------------------

With the ``Insert_Text_With_Encoding`` function, you can insert GD&T (Geometry, Dimension & Tolerance) symbols into your scene. Note that you must have a font, such as the "ts3d" font, that defines PMI (Product Manufacturing Information) symbols. The following code sample below shows how you can insert a runout symbol into HOOPS using the Unicode value as listed the table below::

	#include <wchar.h>

	 HC_Open_Segment("");
		//Setting a font that has GD&T symbols
		HC_Set_Text_Font("name=ts3d, transforms=on, size=0.5 oru");
		
		//Note that we use the hex value for the runout symbol here.
		wchar_t temp[] = {0x2197,0};
		HC_Insert_Text_With_Encoding(0,0,0,"wcs", temp);
		
		HC_Set_Visibility("text=on");
	 HC_Close_Segment();
		
	HC_Update_Display();


.. csv-table::
	:header: "Symbol", "Unicode Hex Value", "GD&T Symbol Name", "Character Name"
	
	.. image:: images/gdt_2194.png, "0x2194", "Between", ""
	.. image:: images/gdt_2197.png, "0x2197", "Circular runout", "North east arrow"
	.. image:: images/gdt_21A7.png, "0x21A7", "Depth/deep", "Downwards arrow from bar"
	.. image:: images/gdt_2220.png, "0x2220", "Angularity", "Angle"
	.. image:: images/gdt_2225.png, "0x2225", "Parallelism", "Parallel to"
	.. image:: images/gdt_2300.png, "0x2300", "Diameter", "Diameter sign"
	.. image:: images/gdt_2312.png, "0x2312", "Profile of a line", "Arc"
	.. image:: images/gdt_2313.png, "0x2313", "Profile of a surface", "Segment"
	.. image:: images/gdt_2316.png, "0x2316", "Position", "Position indicator"
	.. image:: images/gdt_2322.png, "0x2322", "Arc length", ""
	.. image:: images/gdt_232D.png, "0x232D", "Cylindricity", ""
	.. image:: images/gdt_232F.png, "0x232F", "Symmetry", ""
	.. image:: images/gdt_2330.png, "0x2330", "Total runout", ""
	.. image:: images/gdt_2332.png, "0x2332", "Conical taper", ""
	.. image:: images/gdt_2333.png, "0x2333", "Slope", ""
	.. image:: images/gdt_2334.png, "0x2334", "Counterbore", ""
	.. image:: images/gdt_2335.png, "0x2335", "Countersink", ""
	.. image:: images/gdt_23E4.png, "0x23E4", "Straightness", ""
	.. image:: images/gdt_23E5.png, "0x23E5", "Flatness", ""
	.. image:: images/gdt_24BB.png, "0x24BB", "Free state variations", "Circled Latin capital letter F"
	.. image:: images/gdt_24C1.png, "0x24C1", "Least material condition", "Circled Latin capital letter L"
	.. image:: images/gdt_24C2.png, "0x24C2", "Maximum material condition", "Circled Latin capital letter M"
	.. image:: images/gdt_24C5.png, "0x24C5", "Projected tolerance zone", "Circled Latin capital letter P"
	.. image:: images/gdt_24C8.png, "0x24C8", "Regardless of feature size", ""
	.. image:: images/gdt_24C9.png, "0x24C9", "Tangent plane", "Circled Latin capital letter T"
	.. image:: images/gdt_24CA.png, "0x24CA", "Unilateral", ""
	.. image:: images/gdt_25A1.png, "0x25A1", "Square", "White square"
	.. image:: images/gdt_25CE.png, "0x25CE", "Concentricity", "Bullseye"
	.. image:: images/gdt_25EF.png, "0x25EF", "Circularity", "Large circle"
	.. image:: images/gdt_27C2.png, "0x27C2", "Perpendicularity", "Perpendicular"
	.. image:: images/gdt_E400.png, "0xE400", "Statistical tolerance", ""
	.. image:: images/gdt_E401.png, "0xE401", "Third angle projection", ""

*A list of supported GD&T symbols supported in ts3d font and their associated Unicode hex values.*


.. csv-table::
	:header: "Symbol", "Unicode Hex Value", "Character Name"
	
	.. image:: images/gdt_2192.png, "0x2192", ""
	.. image:: images/gdt_2295.png, "0x2295", "Circled plus"
	.. image:: images/gdt_2296.png, "0x2296", "Cirlced minus"
	.. image:: images/gdt_2302.png, "0x2302", ""
	.. image:: images/gdt_2323.png, "0x2323", ""
	.. image:: images/gdt_24BA.png, "0x24BA", ""
	.. image:: images/gdt_24C7.png, "0x24C7", ""
	.. image:: images/gdt_25B3.png, "0x25B3", ""
	.. image:: images/gdt_25CA.png, "0x25CA", ""
	.. image:: images/gdt_25CB.png, "0x25CB", "White circle"
	.. image:: images/gdt_E402.png, "0xE402", ""

*A list of other supported symbols in ts3d font and their associated Unicode hex values.*
