Queries

The real power of AgRt3EntityManager is revealed when you use queries and events to process data. While the primary job of the entity provider is to insert entities into the framework - providing their time, position and any associated metadata - it does not assign any graphical properties to the entities or help you filter the large volume of entities it may be creating; this, in general terms, is the job of the query plugin. More specifically, a query plugin decides whether an entity meets a given criteria, and the AgRt3QueryGraphics object (which is implemented for you) manages the entities and sets their graphical properties.

While you can easily implement your own query plugin, RT3 already provides several: AgRt3DistanceQuery, which queries based on entity distance to known points or each other; AgRt3AreaQuery, which queries entities based on there position inside a pre-defined area; and AgRt3SimpleQuery which queries entities based on their metadata and position. We will use this plugin in all of our examples here. First, we need to create an instance of the query and set its options; this is different for each query plugin. For example:

AgRt3SimpleQuery MyQuery = new AgRt3SimpleQuery();
MyQuery.InstanceName = "My Query";

AgRt3SimpleQueryClause Clause1 = new AgRt3SimpleQueryClause();
Clause1.Field = "Latitude";
Clause1.Value = 0;
Clause1.ComparisonOperand = AgERt3ComparisonOperand.eRt3ComparisonOperandGreaterThan;
Clause1.ConjunctiveOperand = AgERt3ConjunctiveOperand.eRt3ConjunctiveOperandAnd;
MyQuery.Clauses.Add(Clause1 as IAgRt3SimpleQueryClause);

AgRt3SimpleQueryClause Clause2 = new AgRt3SimpleQueryClause();
Clause2.Field = "Altitude";
Clause2.Value = 1000;
Clause2.ComparisonOperand = AgERt3ComparisonOperand.eRt3ComparisonOperandLessThan;
Clause2.ConjunctiveOperand = AgERt3ConjunctiveOperand.eRt3ConjunctiveOperandNone;
MyQuery.Clauses.Add(Clause1 as IAgRt3SimpleQueryClause);

EntityManager.Queries.Add(MyQuery as IAgRt3Query);

In the above example, we created an AgRt3SimpleQuery to show all entities which have a latitude greater than zero and an altitude of less than one thousand meters. We then inserted this query into the entity manager Queries property. Now, all entities matching these criteria will be assigned graphical properties via the AgRt3QueryGraphics object and pushed to the output plugin.

You can modify a query after it has been added to the entity manager, but you must use CommitUpdate in a similar manner to how you update an entity. This CommitUpdate does not take any parameters:

MyQuery.Clauses[0].Value = 2500;
MyQuery.CommitUpdate();

It should be noted that order is important when adding multiple queries to the entity manager query collection. A single entity can only be matched to one query at a time, which creates a waterfall effect. For example, assume you had two queries - the first showed all entities with the metadata field “Friendly” set to true, while the second showed all entities with the metadata field “Helicopter” set to true. When an entity is inserted or updated, the entity manager first checks to see if it has the field “Friendly” set to true; if it does, the entity is added to this query and processing stops. Even if the entity has the “Helicopter” field set to true, it does not matter because it matched a query of higher priority. If an entity did not match the “Friendly’ query, it would then be evaluated for the “Helicopter” query.

Sometimes, you may want to execute a query for informational purposes only without sending anything into the display. In addition, you may want that query to evaluate all entities, not just the ones currently not matched to an existing query. This is the kind of circumstance in which the entity manager ExecuteQuery method can be utilized. Without taking into account any other queries, ExecuteQuery takes a query instance as input and returns all entities which match that query in an AgEntityCollection object. For example, assume your entities had a metadata field named “Fuel” which indicated the number of gallons of fuel left in a ground vehicle. You could create a query named FuelQuery, which specifies all vehicles with less than five gallons of fuel left. You would then retrieve the entities matching this query via ExecuteQuery, as depicted in the example below:

AgRt3SimpleQuery LowFuelQuery = new AgRt3SimpleQuery();
AgRt3SimpleQueryClause Clause = new AgRt3SimpleQueryClause();
Clause.Field = "Fuel";
Clause.ComparisonOperand = AgERt3ComparisonOperand.eRt3ComparisonOperandLessThan;
Clause.Value = 5;
Clause.ConjunctiveOperand = AgERt3ConjunctiveOperand.eRt3ConjunctiveOperandNone;
LowFuelQuery.Clauses.Add(Clause as IAgRt3SimpleQueryClause);
AgEntityCollection Entities = EntityManager.ExecuteQuery(LowFuelQuery);

Query Graphics

So far, we have mentioned AgRt3QueryGraphics, but have not done anything with it yet. AgRt3QueryGraphics is contained in the IAgRt3Query interface as the Graphics property. Properties set in the graphics object will then be mapped into each entity's graphical settings. For example, suppose that you wanted everything within your query to be represented by blue lines and text and that you wanted the marker for the entity to be a Mil2525B symbol (and assuming you already stored this symbol in the entity’s metadata under the name “Symbology”):

MyQuery.MyQuery.Graphics.Color = (uint)ColorTranslator.ToOle(Color.Blue);
ShowAllQuery.Graphics.UseMilField = true;howAllQuery.Graphics.MilField = "Symbology";

Unique dynamic labels can also be generated for each entity in the query. The Labels property is an array of metadata field names which will be used to generate a label. For example, suppose that you had real-time data with sensor information regarding the chemical composition of the air and that you had a metadata field named “Nitrogen” which indicated the percentage of nitrogen in the air that the sensor was detecting:

Array Labels = new object[] {"DisplayName", "Nitrogen"};
SampleQuery.Graphics.set_Labels(ref Labels);
SampleQuery.Graphics.LabelSeparator = ":";

In the above example, RT3 will look up the value of “DisplayName”, and “Nitrogen” for each entity in the query and generate a label with its values. Each field will be separated by “:”. This label will be stored in the Label Text property for each Entity - for example, “Sensor3:78”. Because a single line format may not be optimal for large labels, you can cause a multi-line label to be generated, and optionally have the name of the field be shown next to each value using the following code:

SampleQuery.Graphics.MultiLineLabel = true;
SampleQuery.Graphics.ShowFieldName = true;

This will produce a multi-line label reading:

DisplayName: Sensor3
Nitrogen: 78

It is important to note that labels are completely dynamic. As soon as the entity in the above example is updated, its label will be updated to match. Thus, if the amount of nitrogen in the air changes, so will the label. Many of the other properties are self-explanatory, such as ShowLabels to show and hide the labels for all entities in the query. For a full list of label properties, see RT3 Object Model Reference.

AgRt3QueryGraphics also implements IAgEntityCollection. If you would like to access any of the entities that are currently matched to a given query, simply cast the Graphics property to a collection to access the entities.

Implementing Custom Query Plugins

Only three interfaces are required in order to implement a custom query, IAgRtPlugin, IAgRt3Query and IAgAttrConfig. IAgRt3Query is very simple; the only method of any substance is IsMatch. IsMatch takes an Entity as its only argument and simply returns true or false depending on if the Entity matches the specified query criteria. For example, suppose you wanted to only show entities that had line-of-sight access to a specific location. You would implement your own query plugin that took as its parameters the position you wanted access to:

public bool IsMatch(AGI.Entity.IAgEntity Entity)
{
    //Magic function that tells me if I have line of sight to Entity
    //The implementation of Line of Sight is left up to the user.
    return DoLineOfSightCalculation(m_Position, Entity);
}

A fully documented sample query plugin is located in <STK install folder>Help/RT3/Samples.

STK 11.2.1 Programming Interface