= FDO RFC 60 - Add OGC Annotation Support to the FDO API = This page contains a request for comments document (RFC) for the FDO Open Source project. More FDO RFCs can be found on the [wiki:FDORfcs RFCs] page. == Status == ||RFC Template Version||1.1|| ||Submission Date||April 13, 2011|| ||Last Modified||Greg Boone, April 13, 2011|| ||Author||Greg Boone|| ||RFC Status||Not Ready For Review|| ||Implementation Status||Not Started|| ||Proposed Milestone||3.7.0.0|| ||Assigned PSC guide(s)||Greg Boone|| ||'''Voting History'''||(vote date)|| ||+1|||| ||+0|||| ||-0|||| ||-1|||| == Overview == The RFC is being proposed in order to add formal OGC Annotation Support to the FDO API. Since the FDO API will continue to be used by muliple types of clients as an interchange format, support for annotation/cartographic text will evenetually need to be added to the FDO API, and exposed through our providers. The FDO representation of Annotation Text will be based (as closely as possible) on the OGC specification for cartographic text. The initial requirement would be to support the capabilities of Annotation Text so that the editing representation in our client would round-trip with full fidelity. == Motivation == Spatially placed text is a common requirement of applications. Many application have stored their text placement information in proprietary manners due lack of a consistent and usable standard. Although the mechanisms for text storage have tended to be compatible, the actual format for exchange has been sufficiently different, and, therefore, non-standardized to interfere with complete data exchange and common usage. Annotation text is simply placed text that can carry either geographically-related or ad-hoc data and process-related information is displayable text. This text may be used for display in editors or in simpler maps. It is usually lacking in full cartographic quality, but may act as an approximation to such text as needed by any application. The primary purpose of standardizing this concept is to enable any application using any version of Simple Features data storage or XML to read and write text objects that will describe where and how the text should be displayed. This design ensures that applications that do text placement should have no problem storing their results and that applications that comply with the standard should have no problem exchanging information on text and its placement. Unlike spatial geometries, text display is very dependent on client text rendering engines and the style and layout attributes applied. The spatial area covered by text is only partially determined by the locating geometry. Style and layout attributes along with the actual text and locating geometry are all needed to display text correctly. Thus, it is critical to have a place to store these attributes in the feature database. While it is impossible to guarantee absolute fidelity of display on all rendering systems, applications can interoperate at a useful level. The most common perception of text display is for cartographic purposes, for printed maps of high technical and artistic quality. While this is a potential use of placed text, its more every-day use is for identification of features in any display, regardless of the purpose of that display. So both cartographic preprint and data collection edit displays have a requirement for placed-text, albeit at different levels of artistic quality. The purpose is still the same, to aid in the understanding of the “mapped” features, either for map use or feature edit and analysis. Text can also be used for less precise annotation purposes and more for quick display of text labels that make a display more understandable. The text so placed may not even have any associations to real-world features, but may be used to store information pertinent to the process that the data is undergoing at the moment. Thus, in a data collecting and edit display, a particular placed text may be used to indicate an error in the data that needs to be resolved, such as “sliver,” “gap” and “loop” error in digitization. Here the annotation is placed near the geometric error, but is not necessarily associated to a particular feature, as much as to a portion or portions of feature geometry objects. Annotation text can include text on maps derived from vector information, or text overlays for imagery for information not discernable from the image, such as place or street names. In most cases, applications that do this have certain rules for creating and re-creating text based on the dynamic view of the mapping application. While this standard is not targeted to those usages, there are some allowances for this type of storage if it is so desired. In particular, it is allowable to store text that does not scale with the map objects but instead has a fixed display size (expressed as “points”, 72 to the inch). However, there are some limitations on this usage particularly with spatial indexing. A text object consists of an ordered list of independently placed text elements, possibly corresponding to individual lines of text in a multiline text display, and an envelope that approximates an outer limit of the text elements when placed. Each element has its own text attributes, but they are not used independently. The first element may set the attribute for all following elements and subsequent elements text attributes are only specified when a change is required. This behavior just extends that of the metadata text attributes to each element of the array. A text object consists of a text string and information about its placement. The most important piece of information is the geometry to which the text is to refer, here referred to as the location geometry. A second geometry may be required to visually connect the placed text and the location geometry, especially where the location geometry is crowded in an area with other close-by features. This other geometry is referred to here as a leader line, and is a displayable curve of no geographic significance. If indexing is used, the envelope or minimum bounding box of the text is a handy piece of information that should be available. If unavailable, the envelope can be calculated from the processes of placing the text. Since this is often cumbersome, precalculating the envelope and storing it is often the most efficient manner to use this information. The other information associated to the annotation text is the various style information, such as the size of the text (usually in units appropriate to the display, such as pixels or points), the font used, characteristics of the font. == Proposed Solution == === Supporting Annotations in Existing (Non-FDO) Schema === In order for the FDO API to be able to detect and support Annotation defined in existing schemas such as Oracle, the schema being read must support the Annotation metadata tables as mandated by the OGC Simple Feature Access Specification. The metadata can be exposed as a set of tables or views. ==== OGC Annotation Metadata Table ==== As specified in the OGC Simaple Access Specification, the following CREATE TABLE statement creates an appropriately structured table to be included in the schema, describing how text is stored in a feature table. This should be either an actual metadata table or an updateable view. There is no requirement that the annotated feature have any other attributes. Unattributed annotations are in essence context-free, and may be used to place any text on the data, such as collection metadata or notes to user about unusual situations of which he may wish to be aware. {{{ CREATE TABLE ANNOTATION_TEXT_METADATA AS { F_TABLE_CATALOG AS CHARACTER VARYING NOT NULL, F_TABLE_SCHEMA AS CHARACTER VARYING NOT NULL, F_TABLE_NAME AS CHARACTER VARYING NOT NULL, F_TEXT_KEY_COLUMN AS CHARACTER VARYING NOT NULL, F_TEXT_ENVELOPE_COLUMN AS CHARACTER VARYING NOT NULL, A_ELEMENT_TABLE_CATALOG AS CHARACTER VARYING NOT NULL, A_ELEMENT_TABLE_SCHEMA AS CHARACTER VARYING NOT NULL, A_ELEMENT_TABLE_NAME AS CHARACTER VARYING NOT NULL, A_ELEMENT_TEXT_KEY_COLUMN AS CHARACTER VARYING NOT NULL A_ELEMENT_TEXT_SEQ_COLUMN AS CHARACTER VARYING NOT NULL A_ELEMENT_TEXT_VALUE_COLUMN AS CHARACTER VARYING NOT NULL, A_ELEMENT_TEXT_LEADERLINE_COLUMN AS CHARACTER VARYING NOT NULL, A_ELEMENT_TEXT_LOCATION_COLUMN AS CHARACTER VARYING NOT NULL, A_ELEMENT_TEXT_ATTRIBUTES_COLUMN AS CHARACTER VARYING NOT NULL, A_TEXT_DEFAULT_EXPRESSION AS CHARACTER VARYING, A_TEXT_DEFAULT_ATTRIBUTES AS CHARACTER VARYING } }}} There are no constraints on rows in this table, allowing a single feature table/geometry column pair to be annotated using text from different feature table columns. ==== OGC Annotation Metadata Column Descriptions ==== The fields in the Annotations metadata information view are given in: ||COLUMNS||DESCRIPTION|| ||F_TABLE_CATALOG,[[BR]]F_TABLE_SCHEMA,[[BR]]F_TABLE_NAME||The fully qualified name of the feature table containing the geometry column to be annotated.|| ||F_TEXT_KEY_COLUMN,[[BR]]F_TEXT_KEY_ENVELOPE_COLUMN||The names of the column in the feature table that contain: A KEY for the text to which the text elements can use as a point of aggregation. An ENVELOPE_COLUMN that contains a geometry object that acts as an envelope for the set of text elements in this text entity. This column should also be a valid geometry column.|| ||A_ELEMENT_TABLE_CATALOG,[[BR]]A_ELEMENT_TABLE_SCHEMA,[[BR]]A_ELEMENT_TABLE_NAME||The fully qualified name of the text element table containing the text elements used for the F_Text columns column defined above|| ||A_TEXT_ELEMENT_KEY_COLUMN,[[BR]]A_TEXT_ELEMENT_SEQ_COLUMN,[[BR]]A_TEXT_ELEMENT_VALUE_COLUMN,[[BR]]A_TEXT_ELEMENT_LEADERLINE_COLUMN,[[BR]]A_TEXT_ELEMENT_LOCATION_COLUMN,[[BR]]A_TEXT_ELEMENT_ATTRIBUTES_COLUMN|| The names of the columns in the ELEMENT_TABLE that contain: [[BR]] The foreign KEY for the text entity as specified in the F_TEXT_KEY_COLUMN. [[BR]] A sequence (SEQ) column which will be used to order the text elements in this text entity. Any sortable type is valid for this column in the table, although integers would be the obvious choice. [[BR]] A text string VALUE for this text element. [[BR]] The LEADERLINE for this text element ⎯ if it has one (should also be a geometry column). [[BR]] The LOCATION for this text element (should also be a geometry column). [[BR]] The local text ATTRIBUTES providing the opportunity to override the text attributes currently in force. This is an XML type, and will be a collection of XML elements each describing a text attribute of the current text element. Unspecified attributes take the value most recently defined.|| ||A_TEXT_DEFAULT_EXPRESSION,[[BR]]A_TEXT_DEFAULT_ATTRIBUTES||The default values for the corresponding “A_TEXT_” columns above, for cases where these columns are NULL in the feature table. They may be values or “query” expressions in terms of other columns in the database. These defaults shall be overridden on a row by row basis when the corresponding columns in the feature table row are not NULL.|| === Integrating Annotation Text Concepts into the FDO API === In order to support Annotation Text and the concepts outlined in the sections above, the object and metadata relationships defined by the OGC Simple Feature Access Specification will be incorporated into the FDO API as outlined in the sections below. ==== Annotation Text Definitions as an FDO Property Definition ==== Annotation Text and its logical metadata will be creatable, modifiable and describable via the FDO API schema. Annotation Text will be defined as properties on FDO Feature Classes and be exposed in the same manner as Geometry, Raster and Associations, via an FDO property definition class that derives from !FdoPropertyDefinition. In this manner, class !FdoAnnotationPropertyDefinition will be added to the API and will contain the definition of the schema, classes and properties that define the location of the Annotation components. These elements are the logical properties that are needed to store the annotation text value, envelope, leader line, location and text attributes. The schema, classes and properties identified by these metadata properties will in turn be accessible through their own FDO schema definitions. ===== Starting from an Existing Physical Schema ===== Let us use the following physical schema as a starting point for further discussion. In this example a Road table is used to capture the Location, Name and Width of road objects in a city. Associated to the Road table is a !RoadAnnotation table that contains textual labels that describe the road. A Road object can be associated to 0…n !RoadAnnotation objects. [[Image(road_example.png)]] These two classes are related through their primary identifiers. Road.!FeatId == !RoadAnnotation.!ParentId Road features can be related n times to !RoadAnnotation objects through a combination of matching primary identifiers and the !RoadAnnotation !SequenceId. The full primary key on !RoadAnnotation is therefore a combination of the !ParentId and !SequenceId. The !SequenceId column is used to order the text elements associated to Road. Any sortable type is valid for this column in the table, although integers would be the obvious choice. The !RoadAnnotation table contains a set of properties that are in form (not name) mandated by the OGC specification. These properties, taken together, represent a complete Annotation Text Element. Each Text Element is defined by its Location or spatial geometry, a textual display Value, a textual description of its display model Attributes, and the geographic Leader Line that is used to place the Text Value in relation to its owner or neighboring features. The optional “Text” properties defined on the Road table are also mandated by the OGC Specification. Implementing applications may optionally provide a means of capturing the overall Text Envelope, a Default Text Value and a set of Default Text Attributes to be used to describe all instances of Annotation Text associated to the parent feature. The Default values are used if no values (NULL) are specified for a individual instance of an Annotation object. The Text Default Value may be a text string or a query expression. Text Default Attributes are typically serialized XML documents that describe how to symbolize text entities and their leader lines. In the example above, I show these properties defined on the parent Road table, however, they could in fact be located in any schema:table in the data store and their location and property names described using metadata. Starting from the Road Table described above, let’s construct a simple set of attribute data to represent a Road and several Annotation Text Elements. NOTE: Geometry and Envelope information are not described below. Road Features ||!FeatId||Name||Width||!DefaultTextValue|| ||100||Main St.||25|||| ||200||First Ave.||20|||| ||300||Second Ave.||20||Expr(“Road.Name”)|| !RoadAnnotation Text Elements ||!ParentId||!SequenceId||!TextValue|| ||100||1||“Main St.”|| ||100||2||“Main St.”|| ||200||1||“First Avenue”|| ||200||2||“First Avenue”|| ||200||3||“First Avenue”|| ||300||1|||| ||300||2|||| ===== Physical Schema to FDO Logical Schema ===== From the above Physical Schema, a Logical Schema will be generated that exposes two classes: Feature Class “Road” and Annotation Text Element Class “!RoadAnnotation”. The road table columns will be exposed on the Road Feature Class as Properties. Class Road will also contain a reference to an Annotation property, a new FDO property definition type defined as '''!FdoAnnotationPropertyDefinition'''. The Annotation property will in turn reference a new FDO class type '''!FdoAnnotationTextElementClass''' that defines the instance of the !RoadAnnotation class. [[Image(road_annotation.png)]] Here are the new definitions (simplified property view) of the new !FdoAnnotationTextElement and !FdoAnnotationPropertyDefintion FDO API classes. The full descriptions of these new classes are available in subsequent sections and will specify the Set and Get methods for each class. Each property defined in the two classes described below map to a OGC Annotation construct as outlined in the {{{ class FdoAnnotationTextElementClass : public FdoClassDefinition { public: FdoDataPropertyDefinition* SequenceProperty; FdoDataPropertyDefinition* ParentIdentityProperty; FdoDataPropertyDefinition* TextValueProperty; FdoDataPropertyDefinition* TextAttributesProperty; FdoGeometricPropertyDefinition* GeometryProperty; FdoGeometricPropertyDefinition* LeaderLineProperty; }; }}} {{{ class FdoAnnotationPropertyDefinition : public FdoPropertyDefinition { public: FdoDataPropertyDefinition* FeatureIdentityProperty; FdoDataPropertyDefinition* DefaultTextValueProperty; FdoDataPropertyDefinition* DefaultTextAttributesProperty; FdoGeometricPropertyDefinition* TextEnvelopeProperty; FdoAnnotationTextElementClass* TextElementClass; }; }}} Here are the how these new classes and their respective definitions would map to the Road example specified above. Both Road and !RoadAnnotation are exposed as classes. Road is associated to !RoadAnnotation through an !AnnotationPropertyDefinition named ‘Annotation’. The !AnnotationPropertyDefinition points to the !TextElementClass !RoadAnnotation. ||Property||Value|| ||!AnnotationPropertyDefintion.!TextElementClass||@!RoadAnnotation|| ||!AnnotationPropertyDefintion.!FeatureIdentityProperty||Road.!FeatId|| ||!AnnotationPropertyDefintion.!TextEnvelopeProperty||Road.!TextEnvelope|| ||!AnnotationPropertyDefintion.!DefaultTextValueProperty||Road.!TextDefaultValue|| ||!AnnotationPropertyDefintion.!DefaultTextAttributesProperty||Road.!TextDefaultAttributes|| ||!AnnotationTextElementClass.!SequenceProperty||!RoadAnnotation.!SequenceId|| ||!AnnotationTextElementClass.!ParentIdentityProperty||!RoadAnnotation.!ParentId|| ||!AnnotationTextElementClass.!GeometryProperty||!RoadAnnotation.Location|| ||!AnnotationTextElementClass.!LeaderLineProperty||!RoadAnnotation.!LeaderLine|| ||!AnnotationTextElementClass.!TextValueProperty||!RoadAnnotation.!TextValue|| ||!AnnotationTextElementClass.!TextAttributesProperty||!RoadAnnotation.!TextAttributes|| Through such an organization of Annotation properties into !FdoAnnotationPropertyDefinition and !FdoAnnotationTextElementClass types, multiple Annotation definitions can then be created and added to a single feature class definition, each named uniquely and pointing to a distinct !TextElement class. ===== Enhanced FDO Class and Property Types ===== In order for the !AnnotationTextElement class type to be recognizable when reading an FDO schema, the FDO API Class Type enumeration will be extended to include an enumeration value for type !AnnotationTextElementClass. {{{ enum FdoClassType { FdoClassType_Class, FdoClassType_FeatureClass, ... ... FdoClassType_AnnotationTextElementClass }; }}} This enumerated value will be returned by the implementation of {{{ FdoClassType FdoAnnotationTextElementClass::GetClassType(); }}} In order for the !AnnotationPropertyDefinition type to be recognizable when reading an FDO schema, the FDO API Property Type enumeration will be extended to include an enumeration value for type !AnnotationPropertyDefinition. {{{ enum FdoPropertyType { FdoPropertyType_DataProperty, FdoPropertyType_ObjectProperty, FdoPropertyType_GeometricProperty, FdoPropertyType_AssociationProperty, FdoPropertyType_RasterProperty, FdoPropertyType_AnnotationProperty }; }}} This enumerated value will be returned by the implementation of {{{ FdoPropertyType FdoAnnotationPropertyDefinition::GetPropertyType(); }}} ==== FDO Logical Schema to Physical Schema ==== Using the same FDO classes and physical schema elements introduced in the above sections, here is an FDO code example on how an !ApplySchema Command would be executed to create a physical schema from an FDO logical schema. {{{ // Create the schema FdoFeatureSchemaP schema = FdoFeatureSchema::Create(L"Default", L""); FdoClassCollectionP classes = schema->GetClasses(); // Create the RoadAnnotation TextElements Class FdoAnnotationTextElementClassP txtElementClassDef = FdoAnnotationTextElementClass::Create(L"RoadAnnotation", L""); FdoPropertyDefinitionCollectionP txtElementProps = txtElementClassDef->GetProperties(); FdoDataPropertyDefinitionCollectionP txtElementIdProps = txtElementClassDef->GetIdentityProperties();; // Create a ParentId property to hold the parent ID that owns the text element FdoDataPropertyDefinitionP dataProp = FdoDataPropertyDefinition::Create(L"ParentId", L""); dataProp->SetDataType(FdoDataType_Int32); dataProp->SetNullable(false); dataProp->SetReadOnly(false); dataProp->SetIsAutoGenerated(false); // The ParentId property is a class ID property txtElementProps->Add(dataProp); txtElementIdProps->Add(dataProp); // Explicitly set the ParentId property txtElementClassDef->SetParentIdentityProperty(dataProp); // Create a ParentId property so that Text Elements can be ordered dataProp = FdoDataPropertyDefinition::Create(L"SequenceId", L""); dataProp->SetDataType(FdoDataType_Int32); dataProp->SetNullable(false); dataProp->SetReadOnly(false); dataProp->SetIsAutoGenerated(false); // The SequenceId property is a class ID property txtElementProps->Add(dataProp); txtElementIdProps->Add(dataProp); // Explicitly set the SequenceId property txtElementClassDef->SetSequenceProperty(dataProp); // Create a string data property that will hold the Text Element Value dataProp = FdoDataPropertyDefinition::Create(L"TextValue", L""); dataProp->SetDataType(FdoDataType_String); props->Add(dataProp); // Explicitly set the Text Element Value property txtElementClassDef->SetTextValueProperty(geoProp); // Create a string data property that will hold the Text Element Attributes dataProp = FdoDataPropertyDefinition::Create(L"TextAttributes", L""); dataProp->SetDataType(FdoDataType_String); props->Add(dataProp); // Explicitly set the Text Element Attributes property txtElementClassDef->SetTextAttributesProperty(geoProp); // Create a Geometry Location property for the Text Element FdoGeometricPropertyDefinitionP geoProp = FdoGeometricPropertyDefinition::Create(L"Location", L""); geoProp->SetSpatialContextAssociation(L"EPSG:4326"); geoProp->SetGeometryTypes((int)(FdoGeometryType_Point)); // Point props->Add(geoProp); // Explicitly set the Geometry Location property txtElementClassDef->SetGeometryProperty(geoProp); // Create a Geometry LeaderLine property for the Text Element geoProp = FdoGeometricPropertyDefinition::Create(L"LeaderLine", L""); geoProp->SetSpatialContextAssociation(L"EPSG:4326"); geoProp->SetGeometryTypes((int)(FdoGeometryType_MultiCurveString)); props->Add(geoProp); // Explicitly set the Geometry LeaderLine property txtElementClassDef->SetLeaderLineProperty(geoProp); // Add the class to the schema classes->Add(txtElementClassDef); // Create the Read class FdoFeatureClassP classDef = FdoFeatureClass::Create(L"Road", L""); FdoPropertyDefinitionCollectionP props = classDef->GetProperties(); FdoDataPropertyDefinitionCollectionP idProps = classDef->GetIdentityProperties();; // Create an Annotation property to allow reference to the TextElements FdoAnnotationPropertyDefinitionP annotationProp = FdoAnnotationPropertyDefinition::Create(L"Annotation", L""); props->Add(annotationProp); // Create a Road Identity property dataProp = FdoDataPropertyDefinition::Create(L"FeatId", L""); dataProp->SetDataType(FdoDataType_Int32); dataProp->SetNullable(false); dataProp->SetReadOnly(false); dataProp->SetIsAutoGenerated(true); // The FeatId property is an ID property props->Add(dataProp); idProps->Add(dataProp); // Set the annotation identity property annotationProp->SetIdentityProperty(dataProp); // Create a Name property dataProp = FdoDataPropertyDefinition::Create(L"Name", L""); dataProp->SetDataType(FdoDataType_String); props->Add(dataProp); // Create a Width property dataProp = FdoDataPropertyDefinition::Create(L"Width", L""); dataProp->SetDataType(FdoDataType_Double); props->Add(dataProp); // Create a Geometry to contain the Road location geoProp = FdoGeometricPropertyDefinition::Create(L"Location", L""); geoProp->SetSpatialContextAssociation(L"EPSG:4326"); geoProp->SetGeometryTypes((int)(FdoGeometryType_CurveString)); // CurveString props->Add(geoProp); // Set the geometry property for the class classDef->SetGeometryProperty(geoProp); // Create a Geometry Envelope to contain the TextElements extents geoProp = FdoGeometricPropertyDefinition::Create(L"TextEnvelope", L""); geoProp->SetSpatialContextAssociation(L"EPSG:4326"); geoProp->SetGeometryTypes((int)(FdoGeometryType_CurveString)); // CurveString props->Add(geoProp); // Set the annotation envelope property annotationProp->SetTextEnvelopeProperty(geoProp); // Create a string data property that will hold the default TextElement Value dataProp = FdoDataPropertyDefinition::Create(L"TextDefaultValue", L""); dataProp->SetDataType(FdoDataType_String); props->Add(dataProp); // Explicitly set the Text Element Value property annotationProp->SetDefaultTextValueProperty(dataProp); // Create a string data property that will hold the default TextElement Attributes dataProp = FdoDataPropertyDefinition::Create(L"TextDefaultAttributes", L""); dataProp->SetDataType(FdoDataType_String); props->Add(dataProp); // Explicitly set the Text Element Attributes property annotationProp->SetDefaultTextAttributesProperty(dataProp); // Add the class to the schema classes->Add(classDef); // Execute ApplySchema to create the schema FdoIApplySchemaP applyschema = (FdoIApplySchema*)(connection->CreateCommand(FdoCommandType_ApplySchema)); applyschema->SetIgnoreStates(true); applyschema->SetFeatureSchema(schema); applyschema->Execute(); }}} == Implications == TBD == Test Plan == TBD == !Funding/Resources == Autodesk to provide resources / funding