################
Markup and Views
################

.. sidebar::

   .. contents::
      :local:

In HOOPS Exchange, markup refers to PMI and all the supporting infrastructure related to displaying it with the model.
HOOPS Exchange groups this data into the markup module.
Most markup is represented as tessellation, although certain instances can be represented as either tessellation or semantic data.

.. image:: /_assets/images/example_pmi.png
   :width: 55%

Despite being an important part of the PRC standard, markup is not represented by an entity type.
Instead, one of three *annotation*  entities are used.
Annotation entities are represented by `A3DMkpAnnotationEntity` structures, and the structure can be one of three types:

* **Annotation item**  encapsulates a single markup object. The type is `kA3DTypeMkpAnnotationItem`.
* **Annotation set**  is a group of annotation entities. The type is `kA3DTypeMkpAnnotationSet`.
* **Annotation reference**  is a reference to another annotation. The type is `kA3DTypeMkpAnnotationReference`.

Annotation entities may be present on product occurrences or part definitions.


Parsing Annotation Entities
===========================

The `A3DMkpAnnotationItemData` structure references an `A3DMkpMarkup`.
This markup contains tessellation, leaders, and linked item information that is available by using the function `A3DMkpMarkupGet`.
In addition, this markup can also contain definition data (type information) and specific data (type, leader, linked items, etc.).
This data is stored in a common structure, :c:struct:`A3DMarkupDefinitionData`, and in a specific structure corresponding to the type returned by the function `A3DEntityGetType`.
For the structures corresponding to markup with a definition, only access functions are defined.
In other words, it's only possible to create a `A3DMkpMarkup` object and access the data.

Parsing Tessellation of Markup
------------------------------

Not all files contain semantic PMI, but PMI in tessellated form is always available, so you are guaranteed to at least get a `A3DMkpMarkup` structure.

This is an example of getting the PMI tessellation:

.. code-block:: c
   
   A3DMkpMarkupData markupNodeData;
   A3D_INITIALIZE_DATA(A3DMkpMarkupData, markupNodeData);
   A3DMkpMarkupGet(markupNode, &markupNodeData);
   
   // since tessellation is always available, you can get it from the markupNodeData
   A3DTessMarkupData tessMarkupData;
   A3D_INITIALIZE_DATA(A3DTessMarkupData, tessMarkupData);
   A3DTessMarkupGet(markupNodeData.m_pTessellation, &tessMarkupData);


Parsing Markup Types
--------------------

Different types of markup are possible, such as dimensions, GDT, datum, or text.
All markup will have different information depending on its type, and each type must be parsed accordingly.
Get the type of the markup, and then get the corresponding information (if the markup is a dimension, use `A3DMarkupDimensionGet` to retrieve the information about the dimension):

.. code-block:: c
   
   A3DStatus iRet = A3DEntityGetType(pMarkup, &eType);
   
   iRet = A3DMarkupDefinitionGet((A3DMarkupDefinition*)pMarkup, &sMarkupData);
   if(iRet != A3D_SUCCESS)
   {
	   A3DMarkupDefinitionGet(A3D_NULL_HANDLE, &sMarkupData);
	   return A3D_ERROR;
   }
   
   if(eType == kA3DTypeMarkupText)
   {
	   iRet = A3DMarkupTextGet(pMarkup, &sMarkupData);
   }
   else if(eType == kA3DTypeMarkupRichText)
   {
	   iRet = A3DMarkupRichTextGet(pMarkup, &sMarkupData);
   }
   else if(eType == kA3DTypeMarkupDatum)
   {
	   iRet = A3DMarkupDatumGet(pMarkup, &sMarkupData);
   }
   else if(eType == kA3DTypeMarkupGDT)
   {
	   iRet = A3DMarkupGDTGet(pMarkup, &sMarkupData);
   }
   else if(eType == kA3DTypeMarkupDimension)
   {
	   iRet = A3DMarkupDimensionGet(pMarkup, &sMarkupData);
   }
   else
   {
	   return A3D_NOT_IMPLEMENTED;
   }


Semantic PMI
------------

If the markup is a GDT and has been created in a semantic way in the native CAD software, you can retrieve the semantic information for the Feature Control Frame, using the function `A3DMDSemanticFeatureControlFrameGet`.
If there is no semantic information associated to the GDT, you can still retrieve non-semantic information as text (in `A3DMDFCFDraftingRowData`) using the function `A3DMDFeatureControlFrameGet`.
Note that `A3DMarkupDimension` represents semantic markup.

Parsing Leader Lines
--------------------

If the markup has leader lines, you can retrieve the tessellation of the leaders and, in some cases, linked items associated with the leaders.
Parse it just like you would parse linked items (see below: Linked items associated with markup) or tessellation (see Parsing tessellation of markup).

Linked Items Associated With Markup
===================================

A linked item is a reference from a markup to an entity.
It is stored in an annotation, markup, or view structure.
When a markup contains a link, the link is directed from the annotation entity to a PRC entity.
Linked items can represent a link to any type of entity: a solid, a topological entity, a construction entity,a coordinate system, tessellation, or even another markup.

Each linked item represents a single link.
A markup owns as many linked items as the number of entities it references.
For instance, if you have a dimension line that indicates the distance between two planes, the dimension is a markup object.
It will have two `A3DMiscMarkupLinkedItem` references, and each reference will define a link to a single plane.
See scheme below:

.. image:: /_assets/images/DimensionMarkup.png

Within the linked item object, the member :member:`A3DMiscMarkupLinkedItemData.m_pReference` must be filled with a reference to the object.
`A3DMiscMarkupLinkedItemData` is inherited from `A3DMiscEntityReferenceData`, so :member:`A3DMiscMarkupLinkedItemData.m_pReference` is equivalent to :member:`A3DMiscEntityReferenceData.m_pEntity`.
`A3DMiscEntityReferenceData` is an object containing certain information(e.g., :member:`A3DMiscEntityReferenceData.m_pCoordinateSystem`) and a reference (:member:`A3DMiscEntityReferenceData.m_pEntity`).

:member:`A3DMiscMarkupLinkedItemData.m_pReference` can be a pointer to a Representation Item, a Product Occurrence or a reference to an :struct:`A3DMiscReferenceOnTessData` or :struct:`A3DMiscReferenceOnTopologyData` object.

An example of how to parse linked items can be found in the PRC2XML sample.
In the file *PRC2XMLMarkup.cpp*, see the `traverseLinkedItem` function.
In this example, `pMkpLinkedItem` is cast as a A3DMiscEntityReference:

.. code-block:: c
   
   traverseEntityReference((A3DMiscEntityReference*)pMkpLinkedItem, mkplinkeditem);


Linked Items and Assembly
-------------------------

To help the linked item retrieve the correct entity to reference, the field :member:`A3DMiscMarkupLinkedItemData.m_pTargetProductOccurrence` must be filled with the product occurrence containing the reference.
In case the reference is a part, the Target PO is the one that is holding the part.
If the reference is a subassembly (a sub PO contained in a top-level PO), then the target PO must be the upper level of this subassembly.

.. image:: /_assets/images/LinkedItems_Scheme_Consistent.png

* Linked Item 1.1 references the Part or a subcomponent of the PO A.a.
* m_pReference is a miscellaneous reference to Part or sub-PO, and m_targetPO is a pointer to PO A.a.
* Linked Item 1.2 references the component PO A.a.
* m_pReference is a miscellaneous reference to the PO A.a, and m_targetPO is a pointer to PO A.


:member:`A3DMiscMarkupLinkedItemData.m_pTargetProductOccurrence` can be left null if the markup is located at the same level in the assembly tree as the reference -- i.e., if the markup is held by the same product occurrence as the reference.
HOOPS Exchange will automatically search the entity referenced in the Part, prototype, or sub POs of the PO that owns the markups.

.. image:: /_assets/images/LinkedItemsScheme_TargetPONull.png

* Linked Item A.1.1 references Part A. Part A and Markup A.1 are contained in the same Product Occurrence A, so the m_targetPO can be null.
* Linked Item 1.1 references Product Occurrence A. PO A and Markup 1 are held together on the same level by the root Product Occurrence, so m_targetPO can be null.


A linked item is used to symbolize a link in a very generic manner.
But it is designed to adapt to the constraints of assembly trees.
Hence it will not be possible to link to a reference to a `A3D_PRODUCT_FLAG_CONTAINER` "product occurrence container" located at an equal or higher level in the assembly tree.
This is inconsistent and a bad design because it doesn't correspond to the way CAD files are created.

.. image:: /_assets/images/LinkedItems_Scheme_Inconsistent.png

* Linked Item B.1.1 is inconsistent because it references the assembly file itself, located at a higher level in the assembly tree.
* Linked Item B.1.2 is inconsistent because it references another sub-component of the root assembly. In a CAD file this would be like a part file referencing another part file directly without knowing its place in the assembly file.

Getting Markup Tolerances
-------------------------

A Markup Tolerance can be one of two types:

- :struct:`A3DMDToleranceSizeData`
- :struct:`A3DMDFeatureControlFrameData`

:struct:`A3DMDToleranceSizeData` is a concatenation on a line of dimensions for defining an element. For example, for a hole we can have an :struct:`A3DMDToleranceSizeValueData` for the depth and a :struct:`A3DMDToleranceSizeValueData` for the diameter.
:struct:`A3DMDToleranceSizeValueData` contains a dimension value and A3DEMDDimensionType "an enumerator" specifying type of dimension. And information like the symbol before the value. An instance of :struct:`A3DMDToleranceSizeValueData` can be filled in using :func:`A3DMDToleranceSizeValueGet()`.

These tolerance can be read from the :member:`A3DMarkupGDTData.m_ppsMarkupTolerances` array.

Show and Delete Behaviors
-------------------------

In :struct:`A3DMiscMarkupLinkedItemData`, note the boolean fields such as :member:`A3DMiscMarkupLinkedItemData.m_bMarkupDeleteControl` and :member:`A3DMiscMarkupLinkedItemData.m_bLeaderShowControl`, which enable you to control what happens when a referenced entity is deleted, hidden, or shown.

For example, if the :member:`A3DMiscMarkupLinkedItemData.m_bMarkupDeleteControl` flag is enabled, then the markup will be deleted when the entity is deleted.
Similarly, if the :member:`A3DMiscMarkupLinkedItemData.m_bLeaderShowControl` is enabled, then the markup is shown when the associated entity is shown.

Parsing Views
=============

PMI items are often organized under PMI views.
A PMI view includes a camera and defines a particular model state - often including visibility for particular parts, certain PMI items, highlighted parts, or even parts arranged in an exploded view.
These elements are all managed by linked items.

The purpose of a PMI view is to arrange the model to convey a certain idea.
The HOOPS Exchange type for a PMI view is `A3DMkpViewData`.
This object can be part of a product occurrence or a part definition.

Parsing Annotations
-------------------

Inside the view, :member:`A3DMkpViewData.m_ppAnnotations` allows you to select which annotations to display when the view is selected.
This member can only be filled with annotations defined in the same Product Occurrence as the View.

To select PMI located in child nodes of the Product Occurrence containing the View, use a linked item.

Parsing the Display Scene Parameters
------------------------------------

In the structure :struct:`A3DGraphSceneDisplayParametersData`, you will find information about the graph scene.
Here is a code snippet to retrieve graph scene data:

.. code-block:: c
   
   A3DMkpViewData sData;
   A3D_INITIALIZE_DATA(A3DMkpViewData, sData);
   
   A3DGraphSceneDisplayParameters * pGraphSceneParam = sData.m_pSceneDisplayParameters
   
   A3DGraphSceneDisplayParametersData sData;
   A3D_INITIALIZE_DATA(A3DGraphSceneDisplayParametersData, sData);
   
   A3DInt32 iRet = A3DGraphSceneDisplayParametersGet(pGraphSceneParam, &sData);


Camera, Lights, Styles
----------------------

With the :struct:`A3DGraphCameraData`, you will be able to retrieve information about the position of your camera in the view.
The graph scene parameters also contain information about style, background color, etc.

Cutting Planes
--------------

In the :struct:`A3DGraphSceneDisplayParametersData`, you can find the information related to the clipping planes in the field `m_ppClippingPlanes`.
Here is a code snippet for retrieving the cutting planes of a view:

.. code-block:: c
   
   A3DGraphSceneDisplayParametersData sData;
   A3D_INITIALIZE_DATA(A3DGraphSceneDisplayParametersData, sData);
   
   A3DInt32 iRet = A3DGraphSceneDisplayParametersGet(pGraphSceneParam, &sData);
   for (int ui=0; ui < sData.m_uiPlaneSize; ui++)
	   traverseSrfPlane(sData.m_ppClippingPlanes[ui);


Parsing Linked Items Associated to the View
-------------------------------------------

As previously mentioned, linked items define the view as a particular model state - visibility of particular parts, display of certain PMI items, highlighted parts, or parts arranged in an exploded view.

Visibility of Items and PMI Using Linked Items
----------------------------------------------

For files in an assembly context, it is possible to change the visibility of parts or markups in a view using linked items.

To do this :struct:`A3DMkpViewData` has a linked item array and an annotation array.

To change the visibility of an entity within a particular view, the view must contain a linked item to the desired entity with a new :struct:`A3DRootBaseWithGraphicsData` attached to the linked item: `A3DRootBaseWithGraphicsSet(pLinkedItem, sGraphicsData);`
By default, every markup in the scene will be hidden once a view is selected.
To select which annotations will remain visible, populate the member :member:`A3DMkpViewData.m_ppAnnotations` with pointers to the appropriate annotations.

Position of Items and PMI Using Linked Items
--------------------------------------------

Using a linked item, it's also possible to control the position of an item in a view.

To do this, define a new coordinate system to alter the position of the item.
Fill the :struct:`A3DMiscEntityReferenceData` with the new coordinate and the entity you want to reference.
And set the linked item entity reference in :member:`A3DMiscMarkupLinkedItemData.m_pReference`.

Don't forget to specify the product occurrence to which the item belongs (or set to NULL if the item is at the same level).

Exploded View Sample
--------------------

Here we are creating an exploded view in which one of the model's two Product Occurrences will be "exploded":

.. code-block:: c
   
   // creating the linked item
   A3DMiscMarkupLinkedItem* pMarkupLinkedItem = NULL;
   A3DMiscMarkupLinkedItemData sLinkedItemData;
   A3D_INITIALIZE_DATA(A3DMiscMarkupLinkedItemData, sLinkedItemData);
   
   // setting the target ProductOccurrence to NULL if the reference is at the same level as the PO,
   //    or to the level above if the PO tree has several levels
   sLinkedItemData.m_pTargetProductOccurrence = NULL;
   // setting a non-null reference to create the LI
   sLinkedItemData.m_pReference = sData.m_ppPOccurrences[0];
   
   CHECK_RET(A3DMiscMarkupLinkedItemCreate(&sLinkedItemData, &pMarkupLinkedItem));
   
   // creating the entity reference containing the new coordinate system
   A3DMiscEntityReferenceData sEntityReferenceData;
   A3D_INITIALIZE_DATA(A3DMiscEntityReferenceData, sEntityReferenceData);
   
   // applying the new coordinate system on the first ProductOccurrence
   sEntityReferenceData.m_pEntity = sData.m_ppPOccurrences[0];
   sEntityReferenceData.m_pCoordinateSystem = psRiCoordinateSystem;
   
   // setting the linked item with the new entity reference
   CHECK_RET(A3DMiscEntityReferenceSet(pMarkupLinkedItem, &sEntityReferenceData));
   
   // adding the linked item to the view and creating of the view
   mkpViewData.m_uiLinkedItemsSize = 1;
   mkpViewData.m_ppLinkedItems = (A3DMiscMarkupLinkedItem**)
	   malloc(size_t(mkpViewData.m_uiLinkedItemsSize) * sizeof(A3DMiscMarkupLinkedItem*));
   mkpViewData.m_ppLinkedItems[0] = pMarkupLinkedItem;


To summarize, when determining how a view should be arranged, you must consider three things:

* the markup associated with the view
* the linked items associated with the view (some markup not associated to the view will have its visibility changed in this view)

Not all CAD model files have markup, linked items, or filters in their views.
Some file formats do not support these entities, so your application must decide how to handle each situation based on the type of file you are parsing.

Parsing Filters
---------------

A filter (:struct:`A3DAsmLayerFilterItemData`) can be associated with a view.
One or more layer indexes will be associated to this filter.
The filter contains a flag that defines whether the layers are inclusive or exclusive:

* If inclusive (`A3DAsmLayerFilterItemData::m_bIsInclusive = A3D_TRUE`), all the items are unfiltered, except the ones associated to the layer
* If exclusive (`A3DAsmLayerFilterItemData::m_bIsInclusive = A3D_FALSE`), all the items are filtered except the ones associated to the layer

Each object is associated to a layer in the `GraphicsData`.
In the view, we retrieve the layer indices and determine if they are inclusive or exclusive.
All the objects associated to these layer indices will be filtered (if the layer is inclusive) or unfiltered (and all the objects not associated to the view will be filtered) if the layer is exclusive.

Note that filters are not found in all CAD files, and some file formats don't support them at all.

.. _pmi_units:

Units in Markups
================

Sometimes, semantic markup information can be expressed within the context of a specific unit.
These units are independent from :ref:`the model file unit information <prc_units>`, and are defined at markup level.

In :cpp:struct:`A3DMDDimensionValueFormatData` and :cpp:struct:`A3DMarkupLocatorData`, the field `m_iUnit` is used to represent units of different domains:

* *1*: millimeters
* *2*: inches
* *3*: radians
* *4*: degrees
* *5*: grades

If the value is *UINT32_MAX*, no unit is set and the application should interpret it as using meter for this markup.

Not all markup information needs to have the unit specified.
When a value is provided without units, it is assumed that the :ref:`the model file unit <prc_units>` is used.
As an example, this is the case with :cpp:member:`A3DMDLeaderSymbolData::m_dLength`.
