SpatialRules Developer's Guide

SpatialRules 3.1

ObjectFX®, SpatialFX®, and SpatialRules™ are trademarks of ObjectFX Corporation. All other trademarks are the property of their respective trademark holders.

Various aspects of the SpatialFX technology are covered by one or more of the following U.S. Patents 6,604,046 and 7,010,426 and one or more pending patent applications.

Neither this documentation nor the software it describes may be copied, photocopied, reproduced, modified, translated, or converted to any alternative medium or format in whole or in part, except as explicitly stated in the user's license agreement with ObjectFX Corporation.


Table of Contents

1. Getting Started
1.1. SpatialRules Distribution
1.2. Java Asserts
1.3. Running the Examples
2. Creating Rules
2.1. Features
2.1.1. Reference Features
2.1.2. Feature Sets
2.1.3. Dynamic Features
2.2. Expressions
2.2.1. Creating an Expression
2.2.2. Adding Boolean Operators
2.2.3. Testing for Geometric Relationships
2.2.4. Entering/Exiting
2.2.5. Detecting Proximity
2.2.6. Finding Clusters
2.2.7. Specifying Time Periods
2.2.8. Using Values
2.2.9. Tracking Counts
2.2.10. Detecting Sequences of Events
2.3. Reusing Parts of an Expression
2.4. Using Variables
2.5. Recording Tracks
2.6. Creating Schedules and Intervals
2.7. Adding Expressions to SpatialRules
3. Submitting Dynamic Features
3.1. Rules Service
3.2. Rules Server
3.3. Input Processor
3.3.1. Submitters
3.3.2. Input Processor Database
3.4. Rules Runtime Database
3.5. Aging Data
3.5.1. Age Cleaner
3.5.2. Custom Aging
4. Handling Output
4.1. Results
4.2. Result Handling
4.3. Result Listeners
5. Deployment
5.1. Thread Pool and Queue Configuration
5.1.1. Thread Pools
5.1.2. Queues
5.2. Database Configuration
5.3. Monitoring
5.3.1. Monitoring with SNMP
5.3.2. Monitoring with JMX
A. Script Reference
A.1. and
A.2. attr
A.3. closeTo
A.4. contains
A.5. countGt
A.6. countLt
A.7. coveredBy
A.8. covers
A.9. disjoint
A.10. during
A.11. dynamicFeature
A.12. enters
A.13. eq
A.14. exits
A.15. expression
A.16. extrudedGeometryCollection
A.17. extrudedLine
A.18. extrudedMultiline
A.19. extrudedMultipoint
A.20. extrudedMultipolygon
A.21. extrudedPoint
A.22. extrudedPolygon
A.23. false
A.24. feature
A.25. featureRef
A.26. featureSet
A.27. featureSetRef
A.28. fragment
A.29. fragmentRef
A.30. ge
A.31. geometryCollection
A.32. gt
A.33. inCluster
A.34. intersects
A.35. isIn
A.36. isLike
A.37. le
A.38. line
A.39. list
A.40. lt
A.41. makeTrack
A.42. multiline
A.43. multipoint
A.44. multipolygon
A.45. nOf
A.46. not
A.47. or
A.48. overlaps
A.49. period
A.50. periodRef
A.51. point
A.52. polygon
A.53. property
A.54. recurringTime
A.55. referenceFeature
A.56. regex
A.57. ring
A.58. set
A.59. stateTransition
A.60. transition
A.61. true
A.62. variable
A.63. variableRef
A.64. within
A.65. Arithmetic Operators
A.65.1. Unary Operators
A.65.2. Binary Operators
A.66. Data Types
A.66.1. char
A.66.2. int
A.66.3. long
A.66.4. float
A.66.5. double
A.66.6. date
A.67. Distances
A.68. Time Spans
B. Utilities
B.1. Command-line tools
B.1.1. import
B.1.2. submit
B.1.3. dbadmin
B.1.4. spatialrules
B.2. Cron
B.2.1. Starting Cron
B.2.2. Adding Jobs
B.2.3. Removing Jobs
B.2.4. Getting Results
B.2.5. Stopping Cron
C. Geometries
C.1. Geometry Object Model
C.1.1. Class hierarchy
C.1.2. Geometry
C.1.3. Point
C.1.4. Line String
C.1.5. Linear Ring
C.1.6. Polygon
C.1.7. Multi-Point
C.1.8. Multi-LineString
C.1.9. Multi-Polygon
C.1.10. Geometry Collection
C.1.11. Envelope
C.1.12. Wrapped Envelope
C.2. Spatial Relations
C.2.1. Intersects
C.2.2. Disjoint
C.2.3. Contains/Within
C.2.4. Covers/Covered By
C.2.5. Overlaps
C.3. 3D Geometries
C.4. Boundary Cases
C.4.1. The Anti-Meridian
C.4.2. The Poles
C.4.3. Other Edge Cases
Glossary
Bibliography

List of Figures

2.1. Cluster Overview
2.2. Cluster Outliers Becoming Border
2.3. Clusters with Shared Border Object
2.4. Cluster with Cardinality of Two
2.5. Using MakeTrack to Detect Linear Object Crossing
2.6. Using MakeTrack to Detect Path Interactions
3.1. High Level Process Flow
4.1. Result Publisher/Queue Overview
5.1. Thread Pools and Queues in a Typical Deployment
5.2. Monitoring with SpatialRules SNMP Client
5.3. Monitoring with JConsole
C.1. Geometry Class Hierarchy
C.2. Valid Linear Ring
C.3. Invalid Linear Rings
C.4. Valid Polygons
C.5. Invalid Polygons
C.6. Valid Multi-Polygons
C.7. Invalid Multi-Polygons
C.8. Examples of Contains Relationship
C.9. Examples of Covers Relationship
C.10. Examples of Overlaps Relationship
C.11. Polygon Trying to Span the Anti-meridian
C.12. Polygon Separated into Multi-Polygon
C.13. Region Encompassing the North Pole
C.14. Polygon with Boundary Coordinates

List of Tables

2.1. Comparison of MakeTrack with count vs. time

Chapter 1. Getting Started

1.1. SpatialRules Distribution

SpatialRules is distributed as a ZIP file which contains the following directory structure:

bin

Command-line tools.

doc

Contains all the documentation for SpatialRules.

examples

Contains several examples of how to use SpatialRules.

lib

Contains all of the jar files used by SpatialRules. Only the objectfx-rules-version.jar needs to be on the classpath in most cases.

xml

Contains the XML DTDs and schemas used by SpatialRules. These schemas are required to be on the classpath when using XML-based formats.

rules.properties

The properties file for SpatialRules.

1.2. Java Asserts

SpatialRules takes advantage of Java asserts. Asserts should be enabled during development and quality assurance but turned off during production. The "-ea" command line option is one way to enable them:

java -ea <class>

1.3. Running the Examples

The distribution includes a number of examples that demonstrate how to use and integrate the product. The urban or maritime examples are good places to start. These examples use command-line tools to add reference features and rules to the Rules Database. A data set is then submitted to SpatialRules for analysis.

To run the examples:

  1. Place your license file (rules-license.dat) in the root directory of the distribution so that SpatialRules will find it. If you need to change the name of the file or place it in a different location, change the rules.license.file property in the rules.properties file to specify the new location of the license file.

  2. By default, SpatialRules will create a database in System.getProperty("user.home")/rules-db. To change the location of this database change the rules.db.path property to point to the location where you want the database written.

  3. Uncomment the following line in the rules.properties file and change the "500" to "1".

    #rules.resultlistener.1=com.objectfx.rules.results.ConsoleResultPrinter,AllExpressions,500
  4. Open a command-line window and change to the directory of either examples/urban or examples/maritime.

  5. Start the example by running the runExample.cmd script.

Both of these examples use the command-line import tools to set up reference features and rules. This starts SpatialRules and sends some test data for evaluation against the rules. The output from these examples displays on the server's console. The result handling uses a provided ResultListener named ConsoleResultPrinter that is registered in rules.properties located in the SpatialRules home directory.

The examples/src directory contains other examples for integrating SpatialRules into Java applications. The basic examples ClientSubmitExample and EmbeddedRulesExample are good starting points for application integration. The example ClientSubmitExample shows how to use the InputClient to submit data to a remote instance of SpatialRules. The example EmbeddedRulesExample shows how to integrate SpatialRules services directly into an application. The source code for SpatialRules.java, is included to show you how all of the components in SpatialRules are assembled for its default configuration.

Chapter 2. Creating Rules

2.1. Features

A feature (com.objectfx.feature.Feature) is a georeferenced object. All feature types have the following set of properties:

ID

A unique identifier for the feature. This ID must be unique for all features to get accurate results.

Type

Used to differentiate groups of features. Features with different types usually have different sets of attributes associated with them, for example.

Name

Usually, the common name of a feature and typically used for display only. The name property does not have the uniqueness constraints of the ID property.

Geometry

Describes the feature's size, shape, and position. The geometry could be just a single point or it could be a more complex shape like a line, polygon, or even a geometry collection. See Appendix C, Geometries for details on all the geometries that SpatialRules supports.

Additional attributes (optional)

An arbitrary set of name/value pairs for specifying additional properties for the feature. Names are strings and values are implementations of Comparable (java.lang.Comparable). In SpatialRules, the values must be one of the following types:

  • String (java.lang.String)

  • Integer (java.lang.Integer)

  • Long (java.lang.Long)

  • Float (java.lang.Float)

  • Double (java.lang.Double)

  • Date (java.util.Date)

2.1.1. Reference Features

Reference features are features that are loaded from the RulesDatabase and referenced in expressions by ID. They are usually stationary features such as:

  • Political boundaries

  • Road segments

  • Landmarks

  • Territorial waters

When the RulesService starts up, it reads the reference features into memory. So, you can update a reference feature while the RulesService is running, but you must refresh the RulesService to load the updated version of the reference feature.

To use a reference feature in an expression, you use a feature reference (com.objectfx.feature.FeatureRef) and specify the ID of the feature that you want to reference.

In the following example, we create a simple polygon and load it into the RulesDatabase as a reference feature:

// Open the database in read/write mode.
RulesDatabase db = new RulesDatabase();
db.open(false);

// Create a polygon using these coordinates
double[] xcoords = new double[]{-93.28504425760134, -93.28914266320392,
                                -93.28184399893699, -93.25426525140989,
                                -93.24244146407605, -93.24696669728736,
                                -93.26810267005514};

double[] ycoords = new double[]{44.99598347576073, 44.97599466749296,
                                44.96526126920738, 44.96573856680615,
                                44.98269977564994, 44.99491805950716,
                                45.00049357864552};

Polygon polygon = new Polygon2d(new LinearRing2d(xcoords, ycoords));

// Create a spatial feature by associating a name with the polygon
Feature feature = new SimpleFeature("exampleId", "rulesTarget",
                                    "example label", polygon)

// Add the feature to the rule repository
db.addFeature(feature, true); //replaces an existing feature of this name.

//close the database
db.close();

2.1.2. Feature Sets

A feature set (com.objectfx.feature.FeatureSet) is a simple collection that allows rule logic to be applied across a number of reference features. A feature set is a named group of features that you can reference in an expression so the rule logic is applied to all the features in the group. For example, suppose you wish to monitor exit conditions for each of the 50 U.S. states. Rather than writing 50 expressions, one for each state, you could create a feature set containing all 50 state polygons with the exit condition using the reference to the feature set.

[Note]

If any features in a feature set overlap, a result target set will contain only one of the overlapping features even if there are multiple reference features involved in the evaluation.

When the RulesService starts up, it reads the reference features in the feature set into memory. So, you can update the feature set contents while the RulesService is running, but you must refresh the RulesService to load the new set of reference features.

To use a feature set in an expression, you use a feature set reference (com.objectfx.feature.FeatureSetRef) and specify the ID of the feature set that you want to reference.

The following shows how to create a feature set and add it to the rules database:

// create a named feature set
FeatureSet featureSet = new FeatureSet("example feature set");

// Add spatial feature to the set
featureSet.add(new FeatureRef("exampleId"));

// Add featureSet in the rule repository
rulesDatabase.addFeatureSet(featureSet, false);

2.1.3. Dynamic Features

Dynamic features are the features that are submitted to SpatialRules at runtime. Dynamic features differ from reference features since they represent the state of the feature only at a specific point in time called the captured date. The combination of the dynamic feature's captured date and its geometry forms the feature's location (com.objectfx.rules.Location).

Below is an example of how to create a dynamic feature:

Map<String, Comparable> attributes = new HashMap<String, Comparable>();
attributes.put("speed", new Integer(0));
attributes.put("status", "green");
attributes.put("fuel", new Float(.85));
Location location = new Location(new Point2d(-93.27833, 44.98167), new Date());
new DynamicFeature("Twins Team Bus", "bus", attributes, location);

2.2. Expressions

Expressions encode the conditions that you want to detect on your data stream. The subject of an expression is always the dynamic feature that was submitted, triggering the evaluation of the expression. The target of an expression is the feature or time period against which the subject is being compared. Some expressions like the clustering expression (Section 2.2.6, “Finding Clusters”) or the proximity expression (Section 2.2.5, “Detecting Proximity”) allow you to compare the subject against multiple targets. If an expression returns true, then the subject and all the targets against which the subject was compared will be available in the result (Chapter 4, Handling Output).

There are two basic types of expression: static and dynamic. Static expressions compare the subject's properties (usually the location) against relatively static values such as the location of a reference feature or a time period. On the other hand, dynamic expressions compare the subject's location to the locations of other dynamic features.

You can create expressions in Java or in an ObjectFX language called Script. Script is used to serialize expressions and other objects in SpatialRules. For example, if you export your Rules Database with DbAdmin (Section B.1.3, “dbadmin”), the output file will be written in Script. All of the examples in this section are written in Java, but you can find examples of all of the expressions in Appendix A, Script Reference.

If you choose to write your expressions using Script, the following example illustrates how to use the Script Parser (com.objectfx.script.parser.ScriptParser) to convert the script into Java objects that can be added to the Rules Database

String expression = "<expression in Script>";
List exps = ScriptParser.parse(expression, null);

2.2.1. Creating an Expression

To create a complete expression that you can add to the rules database, you have to add your expression to an expression root (com.objectfx.expression.ExpressionRoot). The expression root takes only two parameters: a name that must be unique to this expression root and the expression against which you want SpatialRules to evaluate each dynamic feature.

For example, to create the simplest expression—one that would evaluate to true for every dynamic feature that was submitted to SpatialRules:

new ExpressionRoot("exp", BooleanExpression.TRUE);

Once your expression has been added to an expression root, it can be saved in Rules Database.

Expression roots can be disabled if you want to leave an expression in Rules Database but not have it active. Below is an example of how to disable an expression:

ExpressionRoot expression = db.getExpression("exp1");
expression.disable();
db.addExpression(expression, true);

2.2.2. Adding Boolean Operators

The boolean operators allow you to combine multiple conditions into an expression. The boolean operators included in SpatialRules are:

and

A binary operator that forms a logical conjunction—its two operands must be true for it to return true: com.objectfx.expression.AndExp.

or

A binary operator that forms a logical disjunction—either of its two operands must be true for it to return true: com.objectfx.expression.OrExp.

not

A unary operator that forms a logical negation—its operand must return false for it to return true: com.objectfx.expression.NotExp.

n of

An n-ary operator that specifies a cardinality—the number of operands that must return true for it to return true: com.objectfx.expression.NOfExp

For example, the following expression would return true whenever a dynamic feature with an attribute of "hazmatClass" whose value was 6 or 7 was at or within the boundary of one of the reference features in the feature set named "population centers":

new AndExp(new CoveredByExp(new FeatureSetRef("population centers")),
           new OrExp(new Equals(new Property("hazmatClass"), new Literal(6)),
                     new Equals(new Property("hazmatClass"), new Literal(7))));

2.2.3. Testing for Geometric Relationships

To test for direct interactions between features, SpatialRules provides both dynamic and static expressions for all supported geometry relations:

intersects

The com.objectfx.expression.leaf.relation.IntersectsExp and com.objectfx.expression.leaf.relation.DynamicIntersectsExp classes provide expressions that check for intersection. See Section C.2.1, “Intersects” for details on the definition of intersection.

disjoint

The com.objectfx.expression.leaf.relation.DisjointExp and com.objectfx.expression.leaf.relation.DynamicDisjointExp classes provide expressions that check for disjoint. See Section C.2.2, “Disjoint” for details on the definition of disjoint.

contains/within

The com.objectfx.expression.leaf.relation.ContainsExp, com.objectfx.expression.leaf.relation.WithinExp, com.objectfx.expression.leaf.relation.DynamicContainsExp and com.objectfx.expression.leaf.relation.DynamicWithinExp classes provide expressions that check for contains and within. See Section C.2.3, “Contains/Within” for details on the definition of contains and within.

covers/covered by

The com.objectfx.expression.leaf.relation.CoversExp, com.objectfx.expression.leaf.relation.CoveredByExp, com.objectfx.expression.leaf.relation.DynamicCoversExp and com.objectfx.expression.leaf.relation.DynamicCoveredByExp classes provide expressions that check for covers and covered by. See Section C.2.4, “Covers/Covered By” for details on the definition of covers and covered by.

overlaps

The com.objectfx.expression.leaf.relation.OverlapsExp and com.objectfx.expression.leaf.relation.DynamicOverlapsExp classes provide expressions that check for overlaps. See Section C.2.5, “Overlaps” for details on the definition of overlaps.

For example, the following expression would return true whenever a dynamic feature of type "weather" with an attribute of "windspeed" whose value was >= 25 intersected with any of the reference features in the feature set "cities":

new AndExp(new GreaterEquals(new Property("/weather/windspeed"),
                             new Literal(25)),
           new IntersectsExp(new FeatureSetRef("cities")));

2.2.4. Entering/Exiting

The enters (com.objectfx.expression.leaf.EntersExp) and exits (com.objectfx.expression.leaf.ExitsExp) expressions allow you to detect when a dynamic feature enters or exits a reference feature.

Enters is detected when a dynamic feature whose previous location was not within (as defined in Section C.2.3, “Contains/Within”) the reference feature but its current location report is. Exits is the inverse: the dynamic feature's previous location report was within the reference feature and its current location report is not.

[Note]

Enters and exits both require at least two location reports for a dynamic feature. If the first report for a dynamic feature is within the reference feature, SpatialRules will not report an enters. Likewise, if the first report is outside the reference feature, it will not report an exits.

To create an enters or exits expression, the only parameter you need is a reference to the reference feature or set:

new EntersExp(new FeatureSetRef("areas of interest"));

2.2.5. Detecting Proximity

To detect when a dynamic feature is close to another feature, use a close-to expression. If the other feature is a reference feature, you use a static close-to expression (com.objectfx.expression.leaf.CloseToExp); if it's another dynamic feature, you use a dynamic close-to expression (com.objectfx.expression.leaf.DynamicCloseToExp).

Both expressions take the following parameters:

distance

A distance (com.objectfx.geometry.Distance) parameter that specifies how close the other feature must be.

feature

For static close-to expressions, a reference to a reference feature (com.objectfx.feature.FeatureRef) or a reference feature set (com.objectfx.feature.FeatureSetRef). For dynamic close-to expressions, a boolean discriminator expression that specifies which dynamic features the subject must be close to.

For example, the following expression will return true any time a subject dynamic feature with an attribute of "cargotype" that has a value of "HAZMAT" comes within one mile of any of the features in the feature set "population centers":

new AndExp(new Equals(new Property("cargotype"),
                      new Literal("HAZMAT")),
           new CloseToExp(
               new Distance(1, LinearUnit.MILES),
               new FeatureSetRef("population centers")));

The dynamic close-to expression can also take two additional parameters:

cardinality

Specifies the number of targets that must be within the specified distance.

timespan

Specifies the maximum allowed time difference between the subject's captured date and the targets' captured date.

For example, the following expression will return true any time a subject dynamic feature of type "A" is located within 50 kilometers of two dynamic features of type "B" whose location captured dates are no more than 30 minutes older than the captured date of the subject:

new AndExp(new Equals(new Property(Attributable.TYPE_ATTR),
                      new Literal("A")),
           new DynamicCloseToExp(
                 new Distance(50, LinearUnit.KILOMETERS),
                 2,
                 new TimeSpan(30, TimeUnits.MINUTES),
                 new Equals(new Property(Attributable.TYPE_ATTR),
                            new Literal("B"))));

2.2.6. Finding Clusters

The cluster (com.objectfx.expression.leaf.InClusterExp) expression is closely related to the dynamic proximity expression: it also looks for the specified number of dynamic features within a certain distance, but it doesn't stop there. If it matches the distance and cardinality constraints for the subject dynamic feature, it performs the same test for each of the target features. If any of the target features match the constraints, it continues on until it runs out of dynamic features that meet the constraints. This set of features is the cluster and the entire set can be included in the result if you want it.

The cluster expression takes the following parameters:

distance

Specifies the distance between the subject of the expression and the targets (i.e. dynamic features)

cardinality

Specifies the number of targets that must be within the required distance to create a cluster.

resolve cluster

Specifies whether all of the members of the cluster should be included in the set of targets in the result

During evaluation of the cluster expression, any dynamic features that are found are put into one of three categories:

core member

Any dynamic feature that meets the cardinality and distance constraints (has the specified number of features within the specified distance) is classified as a core object.

border member

Any dynamic feature that is found within the specified distance of a core member, but doesn't meet the cardinality constraint on its own, is classified as a border object and is considered part of the cluster.

outlier

Any dynamic feature that is not a core or border member and is classified as an outlier and is not considered part of the cluster.

The figure below shows an illustration of a cluster with a cardinality of three.

Figure 2.1. Cluster Overview

Cluster Overview

The figure below shows how the number of features in a cluster jumps from three to five when the addition of a new dynamic feature changes an outlier into a border member of the cluster.

Figure 2.2. Cluster Outliers Becoming Border

Cluster Outliers Becoming Border

The number of features that are members of a cluster is limited to the number of connected (within the specified distance) core members plus any border members. Two clusters cannot be connected by common border members. For example, the figure below shows two different clusters that share a border member.

Figure 2.3. Clusters with Shared Border Object

Clusters with Shared Border Object

If you set the cardinality of the cluster to two you get any of the features that are within the specified distance of one another. In this case, there are no border members since any two features within the specified distance become core members as shown in the figure below.

Figure 2.4. Cluster with Cardinality of Two

Cluster with Cardinality of Two

To limit a cluster expression to a specific subset of the dynamic features, pair it with a comparator (Section 2.2.8.5, “Making Comparisons”) in an And expression:

new AndExp(new Equals(new Property(Attributable.TYPE_ATTR),
                      new Literal("cluster type")),
           new InClusterExp(new Distance(5, LinearUnit.KILOMETERS), 4, false));

2.2.7. Specifying Time Periods

To restrict an expression to a specific period of time, use a during expression (com.objectfx.expression.leaf.DuringExp) that references a period (see Section 2.6, “Creating Schedules and Intervals” for a description of periods). The during expression will only return true if the captured date of the dynamic feature is within the specified time period.

For example, the following expression monitors an area of interest for activity only on the weekend:

new AndExp(new EntersExp(new FeatureRef("area of interest")),
           new DuringExp(new PeriodRef("weekend")));

2.2.8. Using Values

SpatialRules provides a set of expressions that allow you to compare values other than just the geometries of two features. The value expressions described in the following sections allow you to retrieve arbitrary values from features (Section 2.2.8.1, “Properties”), runtime variables (Section 2.2.8.3, “Variable References”), and literals (Section 2.2.8.2, “Literals”). The comparator expressions (Section 2.2.8.5, “Making Comparisons”) described at the end of this section describe the comparisons that you can make.

2.2.8.1. Properties

Property expressions (com.objectfx.expression.value.Property) retrieve values from the attributes of dynamic expressions. A property expression takes only one parameter—the path to the attribute to retrieve. The path parameter uses an Xpath-like syntax to be compatible with [filter-encoding-spec]. There are two forms of the path parameter that you can use. The first is a fully-rooted path that scopes the property expression to dynamic features of the specified type. If the type matches, the property expression will look for the specified property and return the value:

new Property("/<type>/<attribute>");

The second form retrieves the value of the specified property from any dynamic feature:

new Property("<attribute>");

If there is no attribute with the specified name, then null will be returned.

2.2.8.2. Literals

Literal values are added to expression trees by wrapping them with the Scalar Literal (com.objectfx.expression.value.Literal) class. For example, the following statements create literals with date, float, and string data types:

new Literal(new Date());
new Literal(2.71828);
new Literal("string value");

The supported literal types are:

  • integer/Integer

  • long/Long

  • double/Double

  • float/Float

  • String

  • Date (java.util.Date)

2.2.8.3. Variable References

A Variable Reference (com.objectfx.expression.value.VariableRef) allows you to use variable values in expressions. For example, the following variable reference would retrieve the value of the variable named "THREAT_LEVEL":

new VariableRef("THREAT-LEVEL");

See Section 2.4, “Using Variables” for more details on creating and using variables.

2.2.8.4. Math Operations

For numerical values, the Math Operations class (com.objectfx.expression.value.MathOp) provides expressions for most of the Java math operations (java.lang.Math). For example, the first expression below would return the maximum value of its two operands and the second would return the rounded integer of its operand:

new MathOp.Max(new Property("weight"), new Literal(2000));
new MathOp.Rint(new Property("weight"));

2.2.8.5. Making Comparisons

The comparator expressions allow you to compare the values retrieved with the value expressions described above. The supported set of comparisons are listed below:

greater than

Returns true if the left-hand value is greater than the right-hand value.

new GreaterThan(new Literal(.25), new Property("/truck/fill"));

greater than or equal

Returns true if the left-hand value is greater than or equal to the right-hand value.

new GreaterEquals(new Literal(10000), new Property("altitude"));

equal

Returns true if the left- and right-hand values are equal.

new Equals(new VariableRef("alertStatus"), new Literal("red"));

less than or equal

Returns true if the left-hand value is less than or equal to the right-hand value.

new LessEquals(new Property("altitude"), new Literal(10000));

less than

Returns true if the left-hand value is less than the right-hand value.

new LessThan(new Property("/truck/fill"), new Literal(.25));

is like

Returns true if the left-hand value contains the string specified by the regular expression specified in the right-hand value.

new IsLike(new Property("zipCode"), new Regex("^554[0-9]{2}"));

is in

Returns true if the left-hand value is in the collection specified in the right-hand value.

Set<String> watchList = new HashSet<String>();
watchList.add("id1");
watchList.add("id2");
new IsIn(new Property("id"), new Literal(watchList));
[Note]

Comparisons can only be made with like data types. Comparing a string to a date value or a double to an integer value will result in an exception.

2.2.9. Tracking Counts

If you need to monitor the number of features that are within an area for example, you can use the counting expressions: count less than (com.objectfx.expression.leaf.CountLessThanExp) and count greater than (com.objectfx.expression.leaf.CountGreaterThanExp). Both expressions take the following parameters:

count

Is the number of features that the count must exceed or fall below for the expression to be true.

relation expression

A static relation expression (see Section 2.2.3, “Testing for Geometric Relationships”) to specify the spatial relationship that the subject features must have with the target to be counted.

time span

An optional time span that limits the count to a time window. Only those features whose captured date is on or after the date of the most recent feature's captured date minus the time span will be included in the count.

feature discriminator

A boolean expression used to restrict the count to only those dynamic features that match the given expression.

add to targets

A boolean value specifying whether all of the features should be added to the target set when the expression evaluates to true. If you don't need the features or the count is such a high value that reporting all of the features would be problematic, set this value to false.

To monitor for a critical mass scenario, for example, you can use a count greater than expression to alert you when there are more than 50 dynamic features of "monitored type" at least in contact with a "monitored area":

Equals isType = new Equals(new Property(Attributable.TYPE_ATTR),
                           new Literal("monitored type"));
IntersectsExp intersects = new IntersectsExp(new FeatureRef("monitored area"));
CountGreaterThanExp countGt = new CountGreaterThanExp(50, intersects, null, isType, true);

If you only want a count expression to report once when the threshold was crossed, create a pair of count expressions and place them in a state transition expression (see Section 2.2.10, “Detecting Sequences of Events”). The following example creates a state transition expression that monitors an area for a count greater than 50:

CoveredByExp coveredBy = new CoveredByExp(new FeatureRef("monitored area"));
CountGreaterThanExp countGt
   = new CountGreaterThanExp(50, coveredBy, null, BooleanExpression.TRUE, false);
CountLessThanExp countLt
   = new CountLessThanExp(40, coveredBy, null, BooleanExpression.TRUE, false);
List<TransitionExp> transitions = new ArrayList<TransitionExp>();
transitions.add(new TransitionExp("exceeded count", countGt));
transitions.add(new TransitionExp("fell below count", countLt));
StateTransitionExp stateTransition = new StateTransitionExp(transitions);

Once the expression has evaluated to true, it will not be tested again until after the count has fallen below 40 (when the count less than expression evaluates to true). Using a lower value for the count less than expression eliminates any jitter.

2.2.10. Detecting Sequences of Events

To detect a specific sequence of events or just to temporarily disable an expression once it has evaluated to true, you can use a state transition expression (com.objectfx.expression.state.StateTransitionExp). State transition expressions take a list of named expressions called transitions (com.objectfx.expression.state.TransitionExp). Only one of the transitions in the list will be evaluated at a time. When a transition evaluates to true, its ID will be added to the result and the next transition in the list will be the one whose expression is evaluated.

For example, when SpatialRules starts up, the state transition expression marks the first transition in the list as the active transition. SpatialRules will use only the active transition to evaluate dynamic features:

Once the first transition evaluates to true, the second transition is marked as the active transition and all dynamic features are now evaluated against it:

When the second transition evaluates to true, the third transition is marked as the active transition:

When the final transition in the list has evaluated to true, SpatialRules moves the active transition mark back to the first expression in the list to restart the cycle:

A common use for the state transition expressions is with the count expressions (Section 2.2.9, “Tracking Counts”).

2.3. Reusing Parts of an Expression

SpatialRules allows you to store and reference portions of expressions called fragments. A fragment is a logic statement that can be reused across a number of expressions. Fragment definitions by themselves are not evaluated. They must be referenced from a complete expression (ExpressionRoot) for evaluation to take place.

The following example shows how a rule fragment can be constructed using Java and applied to two rules. The fragment determines if any dynamic feature is within 50 meters of any other dynamic feature.

BooleanExpression proximity =
    new DynamicCloseToExp(new Distance(50,
                                       LinearUnit.METERS,
                                       DistanceType.GREAT_CIRCLE),
                          BooleanExpression.TRUE);
ExpressionFragment frag =
         new ExpressionFragment("fragment-example", proximity);
rulesDatabase.addExpressionFragment(frag, false);

The proximity fragment above is then applied to a rule looking for when HAZMAT vehicles are within 50 meters of one another.

Equals eq1 = new Equals(new Property("Restrictions"), new Literal("HAZMAT"));
FragmentRef fragmentRef = new FragmentRef("fragment-example");
AndExp exp1 = new AndExp(eq1, fragmentRef);
ExpressionRoot rule1 = new ExpressionRoot("exp-root1", exp1);
rulesDatabase.addExpression(rule1, false);

The same fragment is then applied to another rule looking for when objects on a WATCH-LIST are within 50 meters of one another.

Equals eq2 = new Equals(new Property("Status"), new Literal("WATCH-LIST"));
AndExp exp2 = new AndExp(eq2, fragmentRef); 
ExpressionRoot rule2 = new ExpressionRoot("exp-root2", exp2); 
rulesDatabase.addExpression(rule2, false);

2.4. Using Variables

In some cases, you might want to be able to adjust the value that an expression is looking for at runtime without having to change the rule and refresh RulesService. To support this, SpatialRules contains another resource called a variable (com.objectfx.expression.value.Variable). To create a variable, you only need to create a new variable instance with a name and an initial default value and add it to the rules database. The variable can then be referenced in a rule during property comparisons or calculations using a VariableRef (com.objectfx.expression.value.VariableRef).

The value of a variable can be changed programmatically through the RulesService instance at runtime. The following example shows how to create a variable called "THREAT-LEVEL". The values correspond to the Department of Homeland Security threat levels:

  • Green

  • Blue

  • Yellow

  • Orange

  • Red

First, create the variable named "THREAT-LEVEL" with an initial value. This variable definition must be added to the rules database:

Variable var = new Variable("THREAT-LEVEL", "GREEN");
rulesDatabase.addVariable(var, false); 

Next, create an expression. One part of the expression detects any dynamic features near another feature of type "hot-spot".

DynamicCloseToExp proximity =
    new DynamicCloseToExp(new Distance(50, LinearUnit.METERS),
                          new Equals(new Literal("hot-spot"),
                                     new Property(Attributable.TYPE_ATTR)));

The rest of the rule checks to see if an attribute called "THREAT-LEVEL" is either "ORANGE" or "RED".

BooleanExpression threatLevel = new OrExp(
   new Equals(new VariableRef("THREAT-LEVEL"), new Literal("ORANGE"));
new Equals(new VariableRef("THREAT-LEVEL"), new Literal("RED")));
AndExp exp = new AndExp(proximity, threatLevel); 
ExpressionRoot rule = new ExpressionRoot("proximity-and-threat", exp); 
rulesDatabase.addExpression(rule, false); 

To alter the variable's value at runtime, reference the RulesService instance and call the setVariable() method. The following example sets the value to "ORANGE".

rulesService.setVariable("THREAT-LEVEL", "ORANGE");

2.5. Recording Tracks

SpatialRules has the ability to collect history on dynamic features that match specified criteria and submit that history as a new dynamic feature using the MakeTrack (com.objectfx.rules.track.MakeTrack) directive. The extent of the history is controlled by either specifying a time range or a count of dynamic feature reports.

A MakeTrack directive requires five parameters:

prefix

The unique name or ID for this MakeTrack that also becomes the prefix for the ID of the track. This prefix is prepended onto the ID of the dynamic feature that is being tracked.

submit original

A boolean value that specifies whether the dynamic feature should also be submitted to the Rules Service (true) or used only for creating a track (false) then discarded.

min

The minimum number of location reports that are required to constitute a track or the minimum time span (the amount of time between the newest and oldest location reports for a feature).

max

The maximum number of location reports that can be in a track or the maximum time span (the amount of time between the newest and oldest location reports for a feature).

feature selector

A boolean expression that selects the features to be tracked.

The minimum parameter indicates how much data is required for SpatialRules to form a track. For example, specifying a minimum of 10 means SpatialRules will not begin submitting tracks for evaluation on a dynamic feature until at least 10 locaiton reports for the dynamic feature are reported. Specifying 10 minutes means that the time between the captured dates for at least two dynamic features is greater than 10 minutes.

Tracks with a minimum count start forming when the min is reached. Subsequent reports are added to the track until the max is reached. The track is maintained with the max count, removing the oldest locations. Tracks with a minimum time start forming only when the time difference between the most recent and the oldest reports exceeds the minimum time. The oldest reports are only trimmed from the track when the difference between them and the most recent exceeds the maximum time. Thus MakeTracks that use time constraints are potentially subject to much greater variance in the number of reports that are actually in the track.

[Note]

Regardless of whether time or a count is used for the minimum a track must be composed of two or more dynamic features (i.e., tracks of one are not allowed).

The table below illustrates the differences between the elements in a track using a min/max count vs. a min/max time.

Table 2.1. Comparison of MakeTrack with count vs. time

Report #Captured DateTrack Contents
CountTime (minutes)
min = 2max = 5min = 10max = 60
112:00:00{}{}
212:06:00{1, 2}{}
312:11:00{1, 2, 3}{1, 2, 3}
412:21:00{1, 2, 3, 4}{1, 2, 3, 4}
513:01:00{1, 2, 3, 4, 5}{2, 3, 4, 5}
613:02:00{2, 3, 4, 5, 6}{2, 3, 4, 5, 6}
713:03:00{3, 4, 5, 6, 7}{2, 3, 4, 5, 6, 7}
813:05:00{4, 5, 6, 7, 8}{2, 3, 4, 5, 6, 7, 8}
914:06:00{5, 6, 7, 8, 9}{}

The min and max values can also be a mix of count and time. The following shows an example that declares a min value of 2 (count of 2 reports) and a max of 2 hours of history. This MakeTrack matches on any dynamic feature containing a property named "MaterialType" that has a value "HAZMAT".

BooleanExpression hazmatVehicles = new Equals(new Literal("HAZMAT"),
                                              new Property("MaterialType"));
final TimeSpan maxTime = new TimeSpan(2, TimeUnits.HOURS);
MakeTrack hazmatTrack = new MakeTrack("HAZMAT-", false, 2, maxTime, hazmatVehicles);

The dynamic features created by MakeTrack are DynamicFeatureTrack instances whose geometry is always a linestring. MakeTrack can be used with features of any supported geometry type, however, only the centroid of the geometry is used to create the track.

It is important to understand that MakeTrack manufactures and maintains a dynamic feature that is derived from the actual dynamic feature submitted to SpatialRules. When a track is submitted, it will have all of the attributes of the most recent report used in the track. Only the ID and the geometry will be different—the ID will have the MakeTrack prefix prepended and the geometry will be the linestring of the track.

Tracks are useful for detecting when objects cross linear objects such as boundaries. For example, in the figure below, a MakeTrack could be paired with an intersection expression to detect when a dynamic feature has crossed a river.

Figure 2.5. Using MakeTrack to Detect Linear Object Crossing

Using MakeTrack to Detect Linear Object Crossing

Tracks are also useful to detect when a dynamic feature crosses the path of another. For example, in the figure below, a MakeTrack could be paired with a close to expression to detect when a ship approaches the path that a previous ship has taken.

Figure 2.6. Using MakeTrack to Detect Path Interactions

Using MakeTrack to Detect Path Interactions

2.6. Creating Schedules and Intervals

Schedules and intervals are specified as periods (com.objectfx.rules.time.Period). A period may cover a fixed interval with a start date/time and end date/time or a recurring schedule. For fixed periods a Java Date (java.util.Date) object is used to define the start and end of the period. A fixed time period may also be open-ended on one end. This allows for specifying a period that begins as of a date or ends as of a date.

To create a period with a fixed range from December 16, 2005 at 12:00 to December 19, 2005 at 18:00:

new Period(DateUtils.createDate("2005-12-16 12:00:00:000 GMT"),
           DateUtils.createDate("2005-12-19 18:00:00:000 GMT"));

A period starting December 16, 2005 12:00 (Pacific Daylight Time) and continuing infinitely into the future:

new Period(DateUtils.createDate("2005-12-16 12:00:00:000 PDT"), null);

A period that includes anything before December 19, 2005 up to 18:00 (Central Standard Time):

new Period(null, DateUtils.createDate("2005-12-19 18:00:00:000 CST"));

Schedules or recurring periods offer the ability to monitor schedules such as weekdays, weekends, every Monday and so forth. The RecurringTime class (com.objectfx.rules.time.RecurringTime) represents the repeating aspects of the period.

An instance of RecurringTime can describe a day-of-week, day-of-month, month-of-year, hour, or minute. At runtime, the rule engine processes recurring times using GMT as the time zone basis. This means that location reports of 16:00 CST (GMT-6) and 14:00 PST (GMT-8) represent the GMT equivalent (they are both specifying 22:00 GMT).

Each component of a recurring time period is represented with an integer (such as Sunday is day 1, Wednesday is day 4 and so forth). The following table shows the ranges for each recurring time component:

Minute

0-59

Hour

0-23

Day of Week

1-7, where Sunday=1

Day of Month

1-31

Month of Year

0-11; where January=0

In cases where the time component should be ignored, null is used. Below are some examples of creating recurring periods:

To create the period from 7:00 AM through 2:59:59 PM daily:

new Period(new RecurringTime(null, "7", null, null, null),
           new RecurringTime(null, "14", null, null, null));

The weekday time period from 12:00 AM Monday through 11:59:59 PM Friday:

new Period(new RecurringTime(null, null, "2", null, null),
           new RecurringTime(null, null, "6", null, null));

The weekday time period from 7:00 AM Monday through 1:59:59 PM Friday:

new Period(new RecurringTime(null, "7", "2", null, null),
           new RecurringTime(null, "13", "6", null, null));

The weekend time period from Saturday, hour 0 through Sunday 11:59:59 PM:

new Period(new RecurringTime(null, null, "7", null, null),
           new RecurringTime(null, null, "1", null, null));

Monday from hour 0 through 11:59:59 PM:

new Period(new RecurringTime(null, null, "2", null, null),
           new RecurringTime(null, null, "2", null, null));

The period from the 7th day of each month through the 15th day of each month:

new Period(new RecurringTime(null, null, null, "7", null),
           new RecurringTime(null, null, null, "15", null));

The period from January 1 at midnight through May 31 at 11:59:59 PM:

new Period(new RecurringTime(null, null, null, null, "0"),
           new RecurringTime(null, null, null, null, "4"));

When you create a recurring period, the RecurringTime instances must both specify the same time slots. For example, you cannot create a period where the start is 6:00 AM and the end time is Monday.

2.7. Adding Expressions to SpatialRules

In order to make an expression available to SpatialRules, the expression must be added to the Rules Database (com.objectfx.rules.database.RulesDatabase) where all of the components of SpatialRules expressions are stored. When Rules Service starts up, it reads all of the enabled expressions and any referenced components from the Rules Database and loads them into memory.

To create an instance of Rules Database, you can use the no-arg constructor and Rules Database will read its configuration properties from the rules.properties file (or use its defaults if none are specified in the properties file). Or you can pass it a properties (java.util.Properties) instance containing the configuration properties that you want to set. See Section 5.2, “Database Configuration” for a list of all the configuration properties. For example:

// Use either defaults or properties from rules.properties file
RulesDatabase defaultDb = new RulesDatabase();

// Use a locally defined set of properties
Properties myProps = new Properties();
myProps.setProperty(RulesDatabase.DB_PATH_PROP_NAME, "/home/me");
RulesDatabase myDb = new RulesDatabase(myProps);

To open the Rules Database, call the open() method:

rulesDatabase.open(false);

The boolean parameter is used to specify whether or not the database should be opened in read-only mode. In the example above, the database is opened in read-write mode.

Once the database has been opened, you can add your expression:

rulesDatabase.addExpression(enterExpression, true);

The first parameter is the expression. The second parameter is a boolean that tells Rules Database whether or not to replace the existing version of the expression if it already exists. If this parameter is false and the expression already exists in the database, an exception is thrown.

Methods for adding, retrieving, updating, and deleting all expression components are included in the Rules Database API (see the API documentation for a complete listing of methods).

Finally, if you are through accessing the Rules Database, you must close it:

rulesDatabase.close();
[Note]

You must call refresh() on any running Rules Service after you make changes to the Rules Database that it is referencing to have it load your changes.

Rules Database can also be accessed remotely through Rules Server by creating an instance of the Rules Admin Client (com.objectfx.rules.server.client.admin.AdminClient) and connecting it to a Rules Server. See the Rules Admin Client API documentation for details of its API.

Chapter 3. Submitting Dynamic Features

SpatialRules is a modular, highly-configurable application. In its default, out-of-the-box configuration, it is set up to support high-volume use cases running as a stand-alone application. Dynamic features are submitted to it from remote hosts and any results are submitted to a message queue or external database. At the other extreme, just two of the components—Rules Service and Rules Database—are all that is required to give any application the ability to detect the spatiotemporal conditions described in Chapter 2, Creating Rules. The default SpatialRules configuration is illustrated in the figure below.

Figure 3.1. High Level Process Flow

High Level Process Flow


Some of the SpatialRules components are inactive by default. Configuration properties in the rules.properties file are used to activate them when needed.

The spatialrules.[sh|cmd] scripts located in <install_dir>/bin will start up SpatialRules in its default configuration. The included source for the SpatialRules class located in <install_dir>/examples/SpatialRules.sh shows how all of the SpatialRules components are managed for this configuration.

The following sections provide an overview of each of the components in the figure above.

3.1. Rules Service

Rules Service (com.objectfx.rules.RulesService) is the active, runtime core of SpatialRules that performs the rule evaluations. Multiple instances of RulesService can be created to run within a single JVM or application. This allows for running multiple Rules Service instances that contain different rules.

To create a new Rules Service, you must give it a Rules Database as the source for its expression components. For example, to create a new Rules Service where the Rules Database gets all of its configuration parameters from the rules.properties file:

RulesService rulesService = new RulesService(new RulesDatabase());

To start the Rules Service, just call the open() method. Rules Service will then read all of the enabled expressions from the Rules Database and initialize all of its indices:

rulesService.open();

If you make any changes to the Rules Database after opening the Rules Service, you will need to call the refresh() method to have Rules Service load the changes:

rulesService.refresh();

To submit dynamic features directly to the Rules Service, you can either pass an instance of Result Handler (com.objectfx.rules.results.ResultHandler) to the submit() method to have any results passed on to it. Or you can get a list of results back directly by just passing the dynamic feature:

// Results passed to the result handler
rulesService.submit(dynamicFeature, resultQueue);

// Results returned directly
List<Result> results = rulesService.submit(dynamicFeature);

To change the values of any variables that are used in any of your expressions, just call the setVariable() method:

rulesService.setVariable("myVar", new Integer(42));

And, when you are through using Rules Service, call the close() method:

rulesService.close();

3.2. Rules Server

In its default operating mode as described above, dynamic features are submitted to SpatialRules via an Input Client (com.objectfx.rules.server.client.input.InputClient) connected to a Rules Server (com.objectfx.rules.server.RulesServer). Rules Server is a dedicated server implementation for receiving dynamic features and administrative commands from remote clients. As features are received, they are placed into a configurable FIFO queue for submission to the Rules Service. Administrative commands submitted by an Admin Client (com.objectfx.rules.server.client.admin.AdminClient) are submitted directly to the Rules Service or its attached Rules Database.

To create a Rules Server instance:

ServerConfig config = ServerConfig.fromProperties();
RulesServer server = new RulesServer(config, rulesService);

The Server Config (com.objectfx.rules.server.ServerConfig) above can read the configuration parameters defined in the rules.properties file or it can be configured programmatically. The configuration parameters are:

hostname

The name of the host on which the server should open a socket. The default is no host, i.e., all interfaces on the current host.

port

The port number on which the server should listen for client connections. The default is 10253.

max connections

The maximum size of the server's thread pool for processing input client requests, i.e., the maximum number of input connections that can be made to the server. The value must be greater than 0 and greater than or equal to the minimum number of threads. The default is 10.

minimum threads

The number of threads the server will always keep ready to handle a new client connection. The default is one.

socket timeout

The length of the timeout value for connections in milliseconds. If the client does not send anything for a period of this length, the connection will be closed. A value of zero disables timeouts. The default is 30000 (30 seconds).

receive buffer size

The size of a server socket's receive buffer in bytes. The default is 65536 (64k)

use TCP_NODELAY

Set TCP_NODELAY on the server's sockets. Refer to your operating system documentation for details. The default is false.

Once instantiated, you only need to call startup() on the instance. When isReady() returns true, the Rules Server is ready to accept connections. When done, just call shutdown().

To connect to a Rules Server and submit dynamic features, you only need to create an Input Client instance, call open() on it, and submit your features:

InputClientConfig config = new InputClientConfig("MyExample");
config.setServerHost("host");
config.setServerPort(10253);
config.setConnectionType(ConnectionType.ASYNC);

InputClient client = new InputClient(config);
client.open();

InputResult inputResult = client.sendFeature(dynamicFeature);
if (inputResult.isError()) {
   System.err.println(inputResult.getErrorMessage());
}

The configuration properties for an Input Client are:

name

A name for the client connection. The name doesn't need to be unique, but it will be used for monitoring on the server.

server host

The host name of the server to which to connect.

server port

The port on the server where Rules Server is listening for connections.

connection type

The type of connection to make. For input clients, only two choices are available: an ASYNC connection will return an Input Result (com.objectfx.rules.server.client.input.InputResult) indicating success or failure and the number of features received. ASYNC_NO_RESPONSE will return nothing. Both of the asynchronous connection types add the dynamic features to the input queue for asynchronous evaluation. For admin clients, only SYNC (execute the command synchronously and return the result) is available.

When you are through submitting features to the server, call close() on the input client to close the connection.

3.3. Input Processor

The InputProcessor (com.objectfx.rules.input.InputProcessor) is the root of a chain of pre-processing steps for dynamic features submitted to Rules Service. Input Processor is a Primary Submitter (com.objectfx.rules.input.PrimarySubmitter) that manages the life cycle of a submitter tree. In addition to forwarding dynamic features to all of its children, it:

  • loads (if not provided as a parameter) the submitter tree specified by the rules.inputprocessor.submitter.<n> properties in the rules.properties file.

  • cascades open() and close() calls to all descendant submitters.

  • creates (if not provided as a parameter), opens, and closes an Input Processor Database if required by one of the descendant submitters.

  • collects up all the Data Maintainers from the descendant submitters.

An Input Processor can be used together with RulesService by adding Rules Service as one of the descendants in the submitter tree. Or it can be used separately by adding a Forwarder to the submitter tree to forward dynamic features on to the machine where a Rules Service instance is running.

If you are using the default SpatialRules configuration, you must set the rules.primary property to enable the Input Processor:

rules.primary=InputProcessor

3.3.1. Submitters

The Submitter interface (com.objectfx.rules.input.Submitter) allows you to create a chain of pre-processing steps through which a feature must pass before being passed on to Rules Service for evaluation. Pre-processing steps could include:

  • filters that selectively discard location reports based on properties, for example, the provided Recency Filter (com.objectfx.rules.input.RecencyFilter) implementations that discards out-of-sequence location reports.

  • enrichment steps that use data from external sources to supplement the attributes that are on an initial location report.

  • routers that submit location reports down different paths based on their properties.

To create a pre-processing step, you create an implementation of the Submitter interface and add it as a descendant of Input Processor. As a simple example, if you wanted to ensure that any out-of-sequence features submitted to the Rules Service were discarded, you would just add a Recency Filter to the pre-processing chain before Rules Service:

// Create a new RulesService--the end of the chain
RulesService rulesService = new RulesService(new RulesDatabase());

// Then add it as a child to a RecencyFilter.
List rulesServiceList = new ArrayList();
rulesServiceList.add(rulesService);
RecencyFilter recencyFilter = new MemoryRecencyFilter(rulesServiceList);

// In turn, add the recency filter as a child to InputProcessor.
// InputProcessor will cascade the open() and close() calls for you.
List recencyFilterList = new ArrayList();
recencyFilterList.add(recencyFilter);

InputProcessor inputProcessor = new InputProcessor(recencyFilterList);
inputProcessor.open();

Recency Filters discard any location report that they receive out of sequence, i.e., one whose captured date is older than the captured date on a previous report for the same feature ID. If the location report is more recent than the last report, a Recency Filter will pass it on to Rules Service.

In the example above, only one child was added to each parent to form a single chain. However, submitters can have multiple children, allowing you to create a tree of pre-processors if you need to. If, for example, you wanted to keep a history of all submitted features, you could create your own Submitter implementation that sends every feature it receives off to be stored in a database. Then all you need to do is add it as an additional child of Input Processor to receive all of the submitted location reports.

To close the Input Processor and all of its descendant submitters, just call the close() method:

inputProcessor.close();

To add a submitter chain to the default SpatialRules configuration, you'll need to use the rules.inputprocessor.submitter.<n>.<p> property. This is a repeating property where the final two segments of the field change for each instance.

The syntax for this property is as follows:

rules.inputprocessor.submitter.<n>.<p>=<classname>[,<param>]*

where

n

An integer that starts at 1 for the first submitter and increments by one for each subsequent submitter. If there is a gap in the sequence an IllegalArgumentException will be thrown.

p

An integer less than n that identifies the submitter that will be the parent of this submitter (the n value of a previous entry. If p is less than n an IllegalArgumentException will be thrown.

classname

The fully qualified name of a class implementing the com.objectfx.rules.input.Submitter interface. This class must also have a constructor that accepts a string array (or a String varargs) as a parameter.

param

Optional parameters to the constructor of classname. They will be be passed in to the constructor as a string array.

For example, to create a simple submitter chain that looked like this:

you would add something like the following properties to your rules.properties file:

rules.primary=InputProcessor
rules.inputprocessor.submitter.1.0=your.package.FeatureRecorder,arg1,arg2
rules.inputprocessor.submitter.2.1=com.objectfx.rules.input.MemoryRecencyFilter
rules.inputprocessor.submitter.3.2=com.objectfx.rules.RulesService

But if you wanted to create something with a tee like the figure below where the feature recorder is on its own branch instead of upstream from the Rules Service:

you would change just change the parent ID of the property entry for the Recency Filter:

rules.primary=InputProcessor
rules.inputprocessor.submitter.1.0=your.package.FeatureRecorder,arg1,arg2
rules.inputprocessor.submitter.2.0=com.objectfx.rules.input.MemoryRecencyFilter
rules.inputprocessor.submitter.3.2=com.objectfx.rules.RulesService

3.3.2. Input Processor Database

Input Processor Database is a data store for all ObjectFX provided Submitter implementations. Currently, the only submitter using the Input Processor Database is the Disk-based Recency Filter (com.objectfx.rules.input.DiskRecencyFilter) which uses the database as a non-persistent, disk-based cache.

Input Processor database has the same configuration properties as other SpatialRules databases as described in Section 5.2, “Database Configuration”

3.4. Rules Runtime Database

Rules Runtime Database is a disk-based cache for some of the SpatialRules internal indexes. Its primary purpose is to support memory-intensive applications that can tolerate some reduction in throughput as index data is written to disk instead of being kept in memory.

Since it is only used as a cache, Rules Runtime Database doesn't have a public API and the data in it is non-persistent. However, it does have the same configuration properties as other SpatialRules databases as described in Section 5.2, “Database Configuration”

Rules Runtime Database is inactive by default. To enable it, you specify which index types you want written to disk. For example, to have the indexes for the enters and exits expressions written to disk[1]:

rules.index.diskbased=ENTERS_EXITS

3.5. Aging Data

During operation, Rules Service maintains information in memory about the dynamic features that have been submitted to it. The amount and type of information depends entirely on the expressions that are active. If your application is working with dynamic featues that have a limited life-cycle[2], you will need to adopt a strategy for aging data—a set of critieria for determining when a dynamic feature is stale, i.e., no longer considered current. If your strategy is the straightforward case of any dynamic feature beyond a certain age is stale, then you should be able to use the provided aging tools described in the next section. For more complex criteria, you will have to implement a custom aging solution as described in Section 3.5.2, “Custom Aging”.

3.5.1. Age Cleaner

SpatialRules provides a built-in data aging mechanism that is configurable through the rules.properties file using the three properties listed below:

rules.cleaner.maxage

The property rules.cleaner.maxage specifies (in minutes) what the maximum acceptable age for a dynamic feature is. For example, the following setting would remove data that is an hour or more old.

rules.cleaner.maxage=60

If a dynamic feature has not been updated for more than an hour it will be removed and no longer be available for rule evaluations. If this property is not set no aging takes place.

rules.cleaner.checkinterval

The property rules.cleaner.checkinterval specifies (in minutes) how often to check for stale data. The default is every 15 minutes, For example, the following specifies that data should be checked every 30 minutes:

rules.cleaner.checkinterval=30

rules.cleaner.loginterval

If aging is enabled, the Rules Service will log the IDs of any features that were removed from the system. The property rules.cleaner.loginterval specifies how long (in minutes) to wait between checks for aging results. The default is an interval four times longer than the check interval. The following specifies an interval of four hours.

rules.cleaner.loginterval=240

3.5.2. Custom Aging

If the default aging mechanism doesn't offer the level of control that your application requires, SpatialRules provides the necessary interfaces and tools for you to add your own aging code and have it run periodically.

The RulesService.getDataMaintainers() method returns a collection of Data Maintainer (com.objectfx.rules.maintainer.DataMaintainer) instances. The Data Maintainer interface provides the methods to inspect and remove dynamic features from SpatialRules. Maintainers provide access to all of the dynamic features currently known and managed by SpatialRules. There may be a number of maintainers for a specific Rules Service instance. Each maintainer corresponds to different types of expression categories. For example, the enters-exits category refers to enter and exit expressions whereas the proximity category refers to closeTo types of expressions. A list of categories is found in the API documentation for the Data Maintainer interface.

The number of maintainers and the number of dynamic feature references within the maintainers is subject to change depending on the data submitted to SpatialRules and the types of expressions currently loaded. For example, if there are no enter or exit expressions loaded there will be no maintainer with a category of enters-exits.

Each maintainer provides access to a set of Dated ID (com.objectfx.rules.maintainer.DatedId) objects. A dated ID contains the ID and timestamp of the dynamic feature. SpatialRules does not fully catalog all data submitted for evaluation. For example, attributes and type information may not be kept. As a result, only the ID and timestamp are available through the maintainer. If your aging strategy requires access to the attributes of the dynamic feature, you will have to look up the dynamic feature in an external data source that maintains the most current dynamic feature.

The following code example shows how to access maintainers and delete dynamic features from SpatialRules.

for (DataMaintainer maintainer : rulesService.getDataMaintainers()) {
  System.out.println("Category: " + maintainer.getExpressionCategory());
  try {
    while (maintainer.hasNext()) {
      DatedId id = maintainer.next();
      if (isTooOld(id)) {
        System.out.println("  Removing ID: " + id.getId()
                           + " Captured Date: " + id.getCapturedDate());
        maintainer.remove();
      }
    }
  } finally {
    maintainer.close();
  }
}


[1] Currently, the only indexes that can be written to disk are the indexes for the enters and exits expressions.

[2] Applications that have features with extended periods of inactivity may also choose to clear out feature data that isn't considered current just to eliminate false positives.

Chapter 4. Handling Output

4.1. Results

As data is processed, any expressions that evaluate to true produce a result (com.objectfx.rules.results.Result). Results have four properties:

Expression Name

The name of the expression that evaluated to true.

Subject

The dynamic feature used to trigger the rule evaluation.

Target Set

The set of targets involved in evaluating the rule. A target might be a reference to a reference feature (or set), a dynamic feature, a dynamic track feature, or a reference to a period. A target set might include a mix of types depending on the expression.

Date

The timestamp when the result was created.

The result is then passed to a result handler (com.objectfx.rules.results.ResultHandler) implementation. Result handlers are described in the next section.

4.2. Result Handling

When Rules Service creates a result, it passes it to a result handler (com.objectfx.rules.results.ResultHandler) implementation. The result handler is responsible for submitting the result to it final destination. There are only two result handler implementations provided with SpatialRules—Result Publisher and Result Queue—both of which are described below. If neither of these works for your application, you will have to create your own implementation.

If you are calling an instance of Rules Service directly from within your own code, just pass your result handler implementation to the RulesService submit(DynamicFeature, ResultHandler) method. Any results that RulesService creates will be passed to your result handler. If you are customizing the SpatialRules.java file, you'll need to pass an instance of your result handler implementation to the Primary Submitter Executor (com.objectfx.rules.PrimarySubmitterExecutor) constructor.

The following UML diagram shows the result handler hierarchy:

The Result Publisher (com.objectfx.rules.results.ResultPublisher) and Result Queue (com.objectfx.rules.results.ResultQueue) are implementations of com.objectfx.rules.results.SubscriptionResultHandler—result handlers that distribute results based on subscriptions. To receive results from the Result Publisher or Result Queue, you create an implementation of a Result Listener (described below) and then subscribe to the results of an expression.

To subscribe a listener, call the subscribe(String, ResultListener) method on the handler. The first argument is either the name of the expression to which you want to subscribe or the string "AllExpressions" if you want the results of all expressions to be published to this listener. A listener can be subscribed to any number of expressions and any number of listeners can be subscribed to an expression.

To add a listener via properties, add an entry to the rules.properties file with the following format:

rules.resultlistener.<n>=<classname>,<expression name>[,<arg>]*

where

n

Is an integer that starts at 1 for the first result listener and increments by one for each result listener. If there is a gap in the sequence, any listeners after the gap will not be loaded. If there are duplicate entries, the last entry listed wins.

classname

Is the fully qualified name of a class implementing the com.objectfx.rules.results.ResultListener interface. This class must also have a constructor that accepts a string array as a parameter.

expression name

Is the name of the expression to whose results this listener is subscribing. Use "AllExpressions" to subscribe to all expressions.

arg

Is an optional parameter to the constructor of classname. Parameters will be be passed in as a string array.

When the handler starts up, it will read the listener properties, instantiate the specified classes, and subscribe them to the specified expressions.

To unsubscribe a listener, call the unsubscribe(String expressionName, ResultListener listener) method on the handler. The first argument is either the name of the expression to which you want to subscribe or the string "AllExpressions". Note that if you subscribed the listener using "AllExpressions" as the expression name, you must unsubscribe using the same string. You cannot subscribe to "AllExpressions" and then unsubscribe from inidividual expressions.

By default, SpatialRules uses the Result Queue to publish results. The Result Queue publishes asynchronously. Its handle() method places the results in a blocking queue instead of publishing them, allowing the calling thread to return. A configurable thread pool monitors the blocking queue and publishes the results to the listeners as they are received.

The Result Publisher publishes results synchronously. When its handle() method is called, the results are published to all subscribed listeners using the calling thread.

The figure below provides an overview of a Result Publisher or Queue publishing results to external systems via listeners.

Figure 4.1. Result Publisher/Queue Overview

Result Publisher/Queue Overview

4.3. Result Listeners

A result listener (com.objectfx.rules.results.ResultListener) implementation forms the connection between SpatialRules and an external service such as an alerting service or data store. There are only three methods to implement on the Result Listener interface:

The open() and close() methods are used to manage external resources such as JMS or JDBC connections. When the Result Queue starts up, it calls the open()method on all of the subscribed result listeners. If the Result Queue is already started when the listener is subscribed, it will call the open() method on it before adding it. When the Result Queue is shut down, it calls close() on all subscribed listeners.

The receive() method is called on the result listener whenever the Result Queue receives a result to which the listener is subscribed.

Chapter 5. Deployment

5.1. Thread Pool and Queue Configuration

SpatialRules uses three thread pools and two queues to manage the flow of dynamic features through the application. Each thread pool and queue has its own configuration options.

The figure below shows the location of the thread pools and queues in a typical SpatialRules deployment.

Figure 5.1. Thread Pools and Queues in a Typical Deployment

Thread Pools and Queues in a Typical Deployment

5.1.1. Thread Pools

5.1.1.1. Connection Thread Pool

The Connection Thread Pool is used to service incoming connection requests from Input and Admin clients. It is the only dynamically sized thread pool with a new thread allocated for each incoming connection. Idle threads from terminated connections are shut down after a period of time if no new incoming request comes in.

The only configuration property for the Connection Thread Pool is rules.server.input.maxconnections. This property allows you to restrict the number of clients that can connect to the Rules Server. The default value is 10.

Connection threads use very little CPU when receiving dynamic features, so adjust the maximum thread count to suit your needs. For example, if you have a lot of short-term connections with spiking volumes, you may need to increase it to 100 or more to allow for the spikes in traffic. On the other hand, you might want to throttle down the spikes by disallowing connections if the total throughput is close to overloading the host machine.

5.1.1.2. Submitter Thread Pool

The Submitter Thread Pool contains the threads that take dynamic features from the Input Queue and submit them to the Input Processor/Rules Service.

The only configuration property for the Submitter Thread Pool is rules.primary.threads. The default value is one.

Submitter threads generally have the most CPU intensive tasks including rule evaluation and reads/writes to the Input Processor and Rules Runtime Databases. In most cases, you should allocate one submitter thread for every CPU core on the host machine for best performance.

5.1.1.3. Result Listener Thread Pool

The Result Listener Thread Pool contains the threads that take results from the Output Queue and submit them to the result listeners.

The only configuration property for the Result Listener Thread Pool is rules.results.queue.threads. The default value is one.

The number of threads that you should allocate to the Result Listener Thread Pool depends on the frequency of results and the latency of the registered listeners.

5.1.2. Queues

A typical SpatialRules deployment has two queues in place to control the flow of objects through the application: the Input Queue and the Output Queue. Both queues have the same three configuration properties described below (each queue has a unique prefix to differentiate the properties):

type

There are three types of queues supported by SpatialRules:

SYNCHRONOUS

A synchronous queue is a blocking queue where each enqueue operation must be followed by a dequeue operation (or vice versa).

When enqueuing to a synchronous queue, if no thread is immediately available to dequeue, the offer timeout property controls what will happen.

BOUNDED

A bounded queue is a blocking queue with a fixed capacity. If the queue's capacity has been reached, the offer timeout property controls what happens to the enqueue operation.

UNBOUNDED

An unbounded queue is a queue with no limit on capacity and no blocking on enqueue operations.

capacity

The maximum capacity of the queue. The capacity property is only used if the queue's type is set to "BOUNDED."

offer.timeout

The offer timeout property specifies the number of milliseconds that the enqueue operation will wait for success. In the case of a bounded queue, this means that space is available in the queue. For a synchronous queue, this means that another thread is waiting to dequeue it. If the enqueue operation has not succeeded in the specified amount of time, it will be aborted and the object that it was trying to enqueue will be dropped.

Setting the offer timeout to "-1", will cause the queue block indefinitely for the enqueue operation to succeed. Setting the offer timeout to "0" means that it must succeed immediately.

5.1.2.1. Input Queue

The Input Queue sits right behind the Rules Server. As dynamic features are received from input connections they are placed on the Input Queue for threads from the Submitter Thread Pool to pick up and submit to the Input Processor/Rules Service.

The default settings for the Input Queue configure it as a synchronous queue with an offer timeout of "-1". In this configuration, if the Submitter Thread Pool falls behind, throughput on the input connections will slow to match the throughput of the Input Processor/Rules Service.

The default settings for all Input Queue properties are as follows:

rules.input.queue.type=SYNCHRONOUS
rules.input.queue.capacity=10000
rules.input.queue.offer.timeout=-1

5.1.2.2. Output Queue

The Output Queue sits right in front of the Result Queue. Whenever a submitter thread receives a result, it attempts to enqueue the result in the Output Queue for distribution to listeners via the threads from the Result Listener Thread Pool.

The default settings for the Output Queue configure it as a bounded queue with a capacty of 2000 and an offer timeout of 20 milliseconds. In this configuration, if the Result Listener Thread Pool falls behind and the Output Queue reaches capacity, results will be discarded if the submitter thread has to wait more than 20 milliseconds for the enqueue operation to succeed.

The default settings for all Output Queue properties are as follows:

rules.results.queue.type=BOUNDED
rules.results.queue.capacity=2000
rules.results.queue.offer.timeout=20

5.2. Database Configuration

All of the SpatialRules databases share a common set of configuration properties described below. Each is differentiated by a prefix specific to a database:

Rules Database

rules.db.

Input Processor Database

rules.inputprocessor.db.

Rules Runtime Database

rules.runtime.db.

The common suffixes for the database configuration parameters are as follows:

path

The path on the filesystem where the database files will be written. This path must be unique to the database instance with some exceptions. The rules are as follows:

  • Only one instance of a read-write database is allowed to be open at a time (across all JVMs).

  • Only one instance of a database may be open at one time per JVM (regardless of read-only or read-write mode).

  • Multiple JVMs can each open one read-only database at the same time.

cache.size

The amount of memory in bytes to allocate to the Berkeley DB cache.

cache.percent

The percentage of JVM memory to allocate to the Berkeley DB cache. Note that this property takes precedence over cache.size.

commit.action

The action to take when a transaction is committed. The choices are:

NO_SYNC

Do not write or synchronously flush the log on transaction commit. This means that transactions will only be written to disk when necessary, e.g., the cache is nearly full. This setting exhibits the least impact on performance. This is the default setting.

WRITE_NO_SYNC

Write but do not synchronously flush the log on transaction commit. This means that transactions will be written to the output stream, but the stream will not be flushed to disk until necessary as above.

SYNC

Write and flush to disk all transactions synchronously. This setting has the most detrimental impact on performance.

cleaner.threads

The number of threads that Berkeley DB will use to clean the database log files. For higher-volume (> 1000 transactions a second) and higher record-count applications, you may need to make this number up to three times the number of threads that are writing to the database.

5.3. Monitoring

SpatialRules provides for remote monitoring of the following values using SNMP (Simple Network Management Protocol) Version 2 and JMX (Java Management Extensions):

  • application status—up or down.

  • number of dynamic features received per connection.

  • number of dynamic features dropped per connection.

  • number of results received by the Result Queue.

  • number of results dropped by the Result Queue.

The details on activating and using remote monitoring are described in the sections below.

SpatialRules also provides a simplistic, log-based method for monitoring. If you set the property rules.monitoring.log.dropped to true in your rules.properties file, then a warn-level message (in the log named "dropped-items.log") will be logged whenever a dynamic feature is dropped at the input queue or a result is dropped at the output queue.

[Note]

Never set rules.monitoring.log.dropped to true on a production machine. If the machine falls behind enough to start dropping features or results, the cost of writing the messages to the log will only compound the problem.

5.3.1. Monitoring with SNMP

5.3.1.1. Enabling the Agent

To enable remote monitoring of SpatialRules with SNMP, add <monitoring_install_dir>/objectfx-rules-snmp-<version>.jar to the SpatialRules classpath by uncommenting and editing the following line in the <rules_install_dir>/bin/launch.cmd file:

rem set CP=%CP%;objectfx-rules-<monitoring implementation>.jar

or the following line in the <rules_install_dir>/bin/launch.sh file:

# CP=${CP};objectfx-rules-<monitoring implementation>.jar

Then, if you need to change any of the default properties for the SNMP connection, copy the <monitoring_install_dir>/rules-snmp.properties file into the root of the rules installation folder and edit the properties as necessary. The properties that you can change are:

rules.snmp.host

Set the host for the SNMP agent to run on. The default is "0.0.0.0"—all interfaces of the current host.

rules.snmp.port

Set the port number for the Agent to use. The default is 161.

rules.snmp.community

Set the community name to use for the SNMP connection. The default is "public"

When you start SpatialRules, it will automatically find and load the SNMP agent so that it can communicate with SNMP clients.

Finally, import the SpatialRules MIB (<monitoring_install_dir>/SPATIAL-RULES-MIB.txt) into your SNMP monitoring tool.

5.3.1.2. Using the SpatialRules SNMP Client

SpatialRules also includes a limited SNMP client that you can start by invoking the snmpviewer.cmd or snmpviewer.sh scripts in the <monitoring_install_dir>/bin folder. To use the client, you must first copy <rules_install_dir>/objectfx-rules-monitoring-<version>.jar to <monitoring_install_dir>/lib.

The arguments to the script are

snmpviewer [-frame] {host} {port} {community name} [polling interval]

The options to the snmpviewer command are as follows:

-frame

If specified, brings up a GUI version of the client as shown in Figure 5.2, “Monitoring with SpatialRules SNMP Client”. If not specified, the values will be written to the console.

host

The name of the host where the SpatialRules SNMP agent is running.

port

The port to use to connect to the SpatialRules SNMP agent.

community name

The community name that the SpatialRules SNMP agent is using ("public" if using default setting).

polling interval

The polling interval in seconds. If specified using the console client, the client will continue to poll the agent and print the current values. If not specified, the console client will print the current values and exit.

Figure 5.2. Monitoring with SpatialRules SNMP Client

Monitoring with SpatialRules SNMP Client

5.3.2. Monitoring with JMX

To enable remote monitoring of SpatialRules with JMX, add <monitoring_install_dir>/objectfx-rules-jmx-<version>.jar to the SpatialRules classpath by uncommenting and editing the following line in the <rules_install_dir>/bin/launch.cmd file:

rem set CP=%CP%;objectfx-rules-<monitoring implementation>.jar

or the following line in the <rules_install_dir>/bin/launch.sh file:

# CP=${CP};objectfx-rules-<monitoring implementation>.jar

Then edit the setting for the JMX_REMOTE variable in the <rules_install_dir>/bin/launch.sh or <rules_install_dir>/bin/launch.cmd file and uncomment the JVMARGS variable:

# Settings for remote monitoring with JConsole. Alter as needed.
JMX_REMOTE="-Dcom.sun.management.jmxremote\
 -Dcom.sun.management.jmxremote.port=10254\
 -Dcom.sun.management.jmxremote.authenticate=false\
 -Dcom.sun.management.jmxremote.ssl=false"

# Uncomment the line below to enable remote monitoring.
#JVMARGS=${JMX_REMOTE}

When you start SpatialRules, it will automatically register its MBean.

To view the values in JConsole, connect to SpatialRules with JConsole and click on the MBean tab and open the com.objectfx tree entry as shown in the figure below.

Figure 5.3. Monitoring with JConsole

Monitoring with JConsole

Appendix A. Script Reference

A.1. and

A boolean expression that returns true if both of its child expressions return true:

(and <boolean expression>, <boolean expression>)

Example:

(and
  (eq (property "/Truck/Restrictions"), "HAZMAT"),
  (eq (property "LEVEL"), (variableRef "CURRENT-THREAT-LEVEL")))

A.3. closeTo

A boolean spatial relation expression that returns true if the subject and the target features are within the specified distance.

There are two forms of the closeTo expression. To test for proximity to a reference features, use this form:

(closeTo <distance>, <featureRef>|<featureSetRef>)

where:

distance

Is one of the distance expressions that specifies how close the subject dynamic feature must be to the target reference feature.

featureRef

Is a reference to a reference feature. See Section A.25, “featureRef”.

featureSetRef

Is a reference to a reference feature set. See Section A.27, “featureSetRef”. The subject dynamic feature only needs to within the specified distance to one of the features in the feature set.

Example:

(closeTo (km "10.0", "greatCircle"), (featureRef "AOI 4"))

To test for proximity to one or more dynamic features, use this form:

(closeTo <distance>, [<cardinality>, <timespan>,] <feature>)

where:

distance

Is one of the distance expressions that specifies how close the subject dynamic feature must be to the target dynamic feature.

cardinality

Is the minimum number of target dynamic features that must be within the specified distance of the subject dynamic feature.

timespan

Is one of the timespan expressions that specifies the maximum age of a target dynamic feature relative to the subject dynamic feature. Any target dynamic feature whose timestamp is more than timespan older than the subject dynamic feature will be excluded from the count.

feature

Is a dynamic feature selector expression. See Section A.24, “feature”.

Example:

(closeTo (mi "6.0", "greatCircle"), (feature true))
(closeTo (m "500.0", "greatCircle"), "4", (minutes "60"), (feature true))

A.4. contains

A boolean spatial relation expression that returns true if a dynamic feature completely contains (see Section C.2.3, “Contains/Within”) a target feature.

(contains <feature>|<featureRef>|<featureSetRef>)

where:

feature

Is a dynamic feature selector expression. See Section A.24, “feature”.

featureRef

Is a reference to a reference feature. See Section A.25, “featureRef”.

featureSetRef

Is a reference to a reference feature set. See Section A.27, “featureSetRef”. The subject dynamic feature only needs to contain one of the features in the feature set.

[Note]

The contains relationship is the inverse of the within relationship.

For example, to determine when a dynamic feature contains a reference feature:

(contains (featureRef "containee"))

Or a dynamic feature contains a previously submitted dynamic feature:

(contains (feature (eq (property "type"), "containee"))

A.5. countGt

A boolean spatial expression that returns true if the number of dynamic features that have the specified spatial relation to an area exceeds the specified value within a specified time.

(countGt "<number>", <relation expression>, <timespan>, <discriminator>)

where:

number

The number of dynamic features that the count must exceed for the expression to evaluate to true.

relation expression

Only the dynamic features that have this geometric relation with the reference feature will be counted. The relation expression must be one of: contains, disjoint, intersects, overlaps, or within.

[Note]

The target feature in the relation expression must be a reference feature. Dynamic relationships are not allowed in count expressions.

timespan

The maximum timespan for the count. Any feature whose timestamp is before the most recently counted feature's timestamp minus this timespan will be dropped from the count. See Section A.68, “Time Spans” for timespan expressions.

discriminator

Only the dynamic features for which the discriminator expression returns true will be counted.

The following example returns true if more than 10 "HAZMAT" trucks are within Zone-A in a 100 hour period.

(countGt "10",
   (within (featureRef "zone-A")),
   (hours "100"),
   (feature (eq (property "/Truck/Restrictions"), "HAZMAT")))

A.6. countLt

A boolean spatial expression that returns true if the number of dynamic features that have the specified spatial relation to an area is less than a specified value within a specified time.

(countLt "<number>", <relation expression>, <timespan>, <discriminator>)

where:

number

The number of dynamic features that the count must fall below for the expression to evaluate to true.

relation expression

Only the dynamic features that have this geometric relation with the reference feature will be counted. The relation expression must be one of: contains, disjoint, intersects, overlaps, or within.

[Note]

The target feature in the relation expression must be a reference feature. Dynamic relationships are not allowed in count expressions.

timespan

The maximum timespan for the count. Any feature whose timestamp is before the most recently counted feature's timestamp minus this timespan will be dropped from the count. See Section A.68, “Time Spans” for timespan expressions.

discriminator

Only the dynamic features for which the discriminator expression returns true will be counted.

The following example returns true if less than 10 "HAZMAT" trucks are within Zone-A in a 100 hour period.

(countLt "10",
   (within (featureRef "zone-A")),
   (hours "100"),
   (feature (eq (property "/Truck/Restrictions"), "HAZMAT")))

A.7. coveredBy

A boolean spatial relation expression that returns true if a dynamic feature is covered by (see Section C.2.4, “Covers/Covered By”) a target feature.

(coveredBy <feature>|<featureRef>|<featureSetRef>)

where:

feature

Is a dynamic feature selector expression. See Section A.24, “feature”.

featureRef

Is a reference to a reference feature. See Section A.25, “featureRef”.

featureSetRef

Is a reference to a reference feature set. See Section A.27, “featureSetRef”. The subject dynamic feature only needs to be covered by one of the features in the feature set.

[Note]

The covered by relationship is the inverse of the covers relationship and is closely related to the within relationship.

For example, to determine when a dynamic feature is covered by a reference feature:

(coveredBy (featureRef "AOI-1"))

Or a dynamic feature is covered by a previously submitted dynamic feature:

(coveredBy (feature (eq (property "type"), "covering feature"))

A.8. covers

A boolean spatial relation expression that returns true if a dynamic feature covers (see Section C.2.4, “Covers/Covered By”) a target feature.

(covers <feature>|<featureRef>|<featureSetRef>)

where:

feature

Is a dynamic feature selector expression. See Section A.24, “feature”.

featureRef

Is a reference to a reference feature. See Section A.25, “featureRef”.

featureSetRef

Is a reference to a reference feature set. See Section A.27, “featureSetRef”. The subject dynamic feature only needs to cover one of the features in the feature set.

[Note]

The covers relationship is the inverse of the covered by relationship and is closely related to the contains relationship.

For example, to determine when a dynamic feature covers a reference feature:

(covers (featureRef "covered"))

Or a dynamic feature covers a previously submitted dynamic feature:

(covers (feature (eq (property "type"), "covered"))

A.9. disjoint

A boolean spatial relation expression that returns true if a dynamic feature is disjoint (see Section C.2.2, “Disjoint”) with a target feature.

[Note]

The disjoint relationship is the negation of the intersects relationship.

(disjoint <feature>|<featureRef>|<featureSetRef>)

where:

feature

Is a dynamic feature selector expression. See Section A.24, “feature”.

featureRef

Is a reference to a reference feature. See Section A.25, “featureRef”.

featureSetRef

Is a reference to a reference feature set. See Section A.27, “featureSetRef”. The subject dynamic feature only needs to be disjoint with one of the features in the feature set, so, although it's allowed, it's probably impractical.

Disjoint with a reference feature:

(disjoint (featureRef "AOI 1"))

Disjoint with a dynamic feature:

(disjoint (feature (eq (property "type"), "tagalong"))

A.10. during

A boolean temporal expression that returns true if a dynamic feature has a captured date that falls within the referenced period.

(during <periodRef>)

Example:

(during (periodRef "Weekend"))

A.11. dynamicFeature

Defines a dynamic feature.

(dynamicFeature "<id>", "<type>", "<name>",
   (location <capturedDate>, <geometry>)[,
   (attr "<key>", "<value>")]*)

where:

id

Is a unique string identifier for the feature.

type

Is a string specifying the feature's type.

name

Is a string specifying the feature's name.

capturedDate

Is a date string as defined in Section A.66.6, “date”.

geometry

Is any supported geometry.

key

Is a string key for an attribute.

value

Is the value for the attribute (use the data types defined in Section A.66, “Data Types”).

For example:

(dynamicFeature "BTA5670", "civil air", "Continental Express 5670", 
  (location
    "2010-04-08 16:25:25.538 CDT",
    (point "-88.25,42.283")), 
  (attr "Route", "KICT./.IRK.BENKY1.KORD/0030"),
  (attr "Airspeed", (int "352")),
  (attr "Altitude", (int "10000")))

A.12. enters

A boolean spatial expression that returns true if a dynamic feature entered a reference feature, i.e., the dynamic feature is within the specified feature for the first time.

(enters <featureRef>|<featureSetRef>)

where:

featureRef

Is a reference to a reference feature. See Section A.25, “featureRef”.

featureSetRef

Is a reference to a reference feature set. See Section A.27, “featureSetRef”. The subject dynamic feature only needs to be disjoint with one of the features in the feature set, so, although it's allowed, it's probably impractical.

Enters the bounds of a reference feature:

(enters (featureRef "state-MN"))

A.13. eq

A boolean comparator expression that returns true if the result of two value expressions are equal:

(eq <value expression>, <value expression>)

where value expression is one of the value expressions, e.g., property, a literal value, or one of the arithmetic operators.

Example:

(eq (property "/Truck/VIN"), "1BXPEI38573")

A.14. exits

A boolean spatial expression that returns true if a dynamic feature exited a reference feature, i.e., the dynamic feature was within the specified feature at its previous location and now isn't.

(exits <featureRef>|<featureSetRef>)

where:

featureRef

Is a reference to a reference feature. See Section A.25, “featureRef”.

featureSetRef

Is a reference to a reference feature set. See Section A.27, “featureSetRef”. The subject dynamic feature only needs to be disjoint with one of the features in the feature set, so, although it's allowed, it's probably impractical.

Exits the bounds of a reference feature:

(exits (featureRef "state-MN"))

A.15. expression

A boolean expression that returns true if its child expression returns true. An expression is used to associate a name with a boolean expression so that it can be evaluated by Rules Service.

(expression "name", <boolean expression>)

Expression names must be unique. Expression names are expressed as literals and may contain any combination of ASCII characters, although control characters should be avoided.

Hint: Using a dot-notation for expression names can be helpful for encoding classification and additional information into the rule that can be parsed during event handling. For example, "us.hazmat.within.7000.meters".

A.16. extrudedGeometryCollection

Defines an extruded geometry collection.

(extrudedGeometryCollection <geometry collection>, "<altitude>", "<height>")

where:

geometry collection

Is a geometryCollection.

altitude

Is the altitude of the base of the geometry collection in meters above sea level.

height

Is the height of the top of the geometry collection in meters above the base.

For example:

(extrudedGeometryCollection 
  (geometryCollection 
    (polygon 
      (ring "-93.12,45.0 -93.04,45.0 -93.04,44.9 -93.15,44.9 -93.16,44.97 -93.12,45.0")),
    (line "0.0,0.0 1.0,1.0 2.0,2.0 3.0,3.0 4.0,4.0"),
    (point "-93.27833,44.98167")),
  "456.45", "1290.76"))

A.17. extrudedLine

Defines an extruded line-string geometry.

(extrudedLine <line>, "<altitude>", "<height>")

where:

line

Is a line.

altitude

Is the altitude of the base of the line in meters above sea level.

height

Is the height of the top of the line in meters above the base.

For example:

(extrudedLine 
  (line "0.0,0.0 1.0,1.0 2.0,2.0 3.0,3.0 4.0,4.0"),
  "480.0", "150.0")

A.18. extrudedMultiline

Defines an extruded multiline.

(extrudedMultiline <multiline>, "<altitude>", "<height>")

where:

multiline

Is a multiline.

altitude

Is the altitude of the base of the multiline in meters above sea level.

height

Is the height of the top of the multiline in meters above the base.

For example:

(extrudedMultiline 
  (multiline 
    (line "0.0,0.0 1.0,1.0 2.0,2.0 3.0,3.0 4.0,4.0"),
    (line "0.0,1.0 1.0,2.0")),
  "10000.0", "100.0")

A.19. extrudedMultipoint

Defines an extruded multipoint.

(extrudedMultipoint <multipoint>, "<altitude>", "<height>")

where:

multipoint

Is a multipoint.

altitude

Is the altitude of the base of the multipoint in meters above sea level.

height

Is the height of the top of the multipoint in meters above the base.

For example:

(extrudedMultipoint 
  (multipoint 
    (point "-93.27833,44.98167"),
    (point "4.1,1.0"),
    (point "0.0,0.0")),
  "1000.0", "10000.0")

A.20. extrudedMultipolygon

Defines an extruded multipolygon.

(extrudedMultipolygon <multipolygon>, "<altitude>", "<height>")

where:

multipolygon

Is a multipolygon.

altitude

Is the altitude of the base of the multipolygon in meters above sea level.

height

Is the height of the top of the multipolygon in meters above the base.

For example:

(extrudedMultipolygon 
  (multipolygon 
    (polygon 
      (ring "-93.12,45.0 -93.04,45.0 -93.04,44.9 -93.15,44.9 -93.16,44.97 -93.12,45.0")),
    (polygon 
      (ring "-93.3,45.0 -93.17,45.02 -93.2,44.909 -93.33,44.893 -93.36,44.956 -93.3,45.0"),
      (ring "-93.31,44.95 -93.32,44.94 -93.32,44.939 -93.3,44.946 -93.31,44.95"),
      (ring "-93.31,44.926 -93.313,44.91 -93.297,44.925 -93.31,44.926"))),
  "0.0", "300.0")

A.21. extrudedPoint

Defines an extruded point geometry.

(extrudedPoint <point>, "<altitude>", "<height>")

where:

point

Is a point.

altitude

Is the altitude of the base of the point in meters above sea level.

height

Is the height of the top of the point in meters above the base.

For example:

(extrudedPoint 
  (point "-93.27833,44.98167"),
  "250.0", "500.0")

A.22. extrudedPolygon

Defines an extruded polygon geometry.

(extrudedPolygon <polygon>, "<altitude>", "<height>")

where:

polygon

Is a polygon.

altitude

Is the altitude of the base of the polygon in meters above sea level.

height

Is the height of the top of the polygon in meters above the base.

For example:

(extrudedPolygon 
    (polygon 
      (ring "-93.12,45.0 -93.04,45.0 -93.04,44.9 -93.15,44.9 -93.16,44.97 -93.12,45.0")),
    "1045.0", "30.0")

A.23. false

A boolean expression that always returns false.

(and false, true)

A.24. feature

A value expression that selects dynamic features. This expression is used as a discriminator in dynamic spatial expressions.

All previously reported dynamic features are evaluated against the child boolean expression. Any feature that evaluates to true will be returned by the feature expression and evaluated by the parent expression.

(feature <boolean expression>)

For example, to scope a rule to only dynamic features of type "truck":

(feature
  (eq (property "type"), "truck"))

Or to scope a rule to only dynamic features with a "HAZMAT" restriction:

(feature
  (eq (property "Restrictions"), "HAZMAT"))

To return all dynamic features, use the true expression:

(feature true)

A.25. featureRef

Denotes a reference (by id) to a reference feature in the rule repository.

(featureRef "<feature id>")

Example:

(featureRef "state-MN")

A.26. featureSet

Defines a set of one or more features in the rule repository. Feature sets are purely a grouping mechanism; expressions are independently evaluated against each feature in the set.

(featureSet "<id>", "<feature id>"[, "<feature id>"]*)

where:

id

The unique ID for the feature set.

feature id

The ID of a reference feature that is stored in the Rules Database.

Example:

(featureSet "fs-states Mid Atl", "state-NY", "state-PA", "state-NJ")

A.27. featureSetRef

Denotes a reference (by id) to a featureSet in the rule repository.

(featureSetRef "<feature set id>")

Example:

(featureSetRef "fs-states Mid Atl")

A.28. fragment

Defines an expression that can be used as part of a larger expression.

(fragment "<name>", <boolean expression>)

where:

name

Is the unique name for this fragment.

boolean expression

Is any boolean expression except for expression.

Example:

(fragment "truckType", (eq (property "type"), "truck"))

A.29. fragmentRef

Denotes a reference (by name) to an expression fragment in the rule repository.

(fragment "<fragment name>")

Example:

(expression "truck enters Mid Atl states",
  (and
    (fragmentRef "truckType"),
    (enters (featureSetRef "fs-states Mid Atl"))
  )
)

A.30. ge

A boolean comparator expression that returns true if the left-hand value expression (first child) is greater than or equal to the right-hand value expression (second child).

(ge <value expression>, <value expression>)

where value expression is one of the value expressions, e.g., property, a literal value, or one of the arithmetic operators.

Example:

(ge (property "/Truck/stops"), (int "3"))

A.31. geometryCollection

Defines a geometry collection.

(geometryCollection <geometry>[, <geometry>]*)

where the geometry arguments are any combination of geometry types.

For example:

(geometryCollection 
  (polygon 
    (ring "-93.12,45.0 -93.04,45.0 -93.04,44.9 -93.15,44.9 -93.16,44.97 -93.12,45.0")),
  (line "0.0,0.0 1.0,1.0 2.0,2.0 3.0,3.0 4.0,4.0"),
  (point "1.0,2.1")))

A.32. gt

A boolean comparator expression that returns true if the left-hand value expression (first child) is greater than the right-hand value expression (second child).

(gt <value expression>, <value expression>)

where value expression is one of the value expressions, e.g., property, a literal value, or one of the arithmetic operators.

Example:

(gt (property "/Truck/stops"), (int "3"))

A.33. inCluster

A boolean spatial expression that returns true when it detects a cluster of dynamic features with the specified minimum number of dynamic features within the specified distance.

(inCluster <distance>, "<count>")

where:

distance

Is one of the distance expressions that specifies the maximum distance between cluster members.

count

Is an integer that specifies the minimum number of members that must be present.

For example, to specify a cluster of 3 or dynamic features within 100 meters of each other:

(inCluster (m "100.0"), "3")

To limit the cluster to only dynamic features meeting specific criteria, combine the cluster expression with a property expression. For example, to limit a cluster to dynamic features with a HAZMAT restriction:

(and
  (inCluster (m "100.0"), "3"),
  (eq
    (property "Restrictions"), "HAZMAT")))

A.34. intersects

Returns true if a dynamic feature intersects (see Section C.2.1, “Intersects”) a target feature.

(intersects <feature>|<featureRef>|<featureSetRef>)

where:

feature

Is a dynamic feature selector expression. See Section A.24, “feature”.

featureRef

Is a reference to a reference feature. See Section A.25, “featureRef”.

featureSetRef

Is a reference to a reference feature set. See Section A.27, “featureSetRef”. The subject dynamic feature only needs to be intersect one of the features in the feature set.

For example, to detect when a dynamic feature intersects a reference feature:

(intersects (featureRef "AOI 2"))

Or when a dynamic feature intersects another dynamic feature:

(intersects (feature
  (gt
    (property "Contamination-Level"),
    (variableRef "CurrentLevel"))))

A.35. isIn

A boolean comparator expression that returns true when the result of the left-hand value expression is a member of the collection returned by the right-hand value expression.

(isIn <scalar value expression>, <collection value expression>)

where:

scalar value expression

Is a value expression that returns a single value.

collection value expression

Is a value expression that returns a collection. (Currently, this means only the collection literals set and list.)

For example:

(isIn
  (property "id"),
  (set "watchId3", "watchId2", "watchId1"))

A.36. isLike

A boolean comparator expression that returns true when the result of the left-hand value expression (first child) is matched by the right-hand (second child) regular expression.

(isLike <value expression>, (regex <regex>))

where:

value expression

Is one of the value expressions, e.g., property, a literal value, or one of the arithmetic operators.

regex

Is a regular expression as documented in java.util.regex.Pattern.

For example, the following matches on Hostile, Unknown and Suspect variations of a military M2525B symbology code starting with the pattern S_PP, where the "_" could be an H, U, or S.

(isLike (property "code"), (regex "S[HUS]PP.*"))

In this example the following codes match the regular expression:

"SHPP------*****"
"SUPP------*****"
"SSPP------*****"

The code "SFPP------*****" would not match.

A.37. le

A boolean comparator expression that returns true if the left-hand value expression (first child) is less than or equal to the right-hand value expression (second child).

(le <value expression>, <value expression>)

where value expression is one of the value expressions, e.g., property, a literal value, or one of the arithmetic operators.

Example:

(le (property "/Truck/stops"), (int "3"))

A.38. line

Defines a line-string geometry.

(line "<lon>,<lat> [<lon>,<lat>]+)

where:

lon

The longitude in decimal degrees as an easting, i.e., longitudes east of the Prime Meridian are positive; longitudes west are negative.

lat

The latitude in decimal degrees as a northing, i.e., latitudes north of the Equator are positive; latitudes south are negative.

[Note]

All geometry coordinates in SpatialRules must be in the CRS defined in Appendix B.3 of [wms-spec].

For example:

(line "0.0,0.0 1.0,1.0 2.0,2.0 3.0,3.0 4.0,4.0")

A.39. list

An ordered collection of values.

(list (<value>[, <value>]*]?)

where value is a literal value using one of the data types listed in Section A.66, “Data Types”.

A.40. lt

A boolean comparator expression that returns true if the left-hand value expression (first child) is less than the right-hand value expression (second child).

(lt <value expression>, <value expression>)

where value expression is one of the value expressions, e.g., property, a literal value, or one of the arithmetic operators.

In the example below, the expression will return true if the value of the "arrival" attribute on a dynamic feature of type "Truck" is a date before 10AM Feb 18, 2008 Eastern Standard Time:

(lt
  (property "/Truck/arrival"),
  (date "2008-02-18 10:00:00:000 EST"))

A.41. makeTrack

An expression that directs SpatialRules to maintain a history track for dynamic features matching the provided feature filter. The track length may be specified by count, time span, or a combination of both. When enough locations for a dynamic feature have been recorded to meet the specified criteria, the track will be submitted as a new dynamic feature.

(makeTrack "<prefix>", "<resubmit>", <min>, <max>, <feature>)

where:

prefix

Is a unique identifier for the expression that will be prepended onto the ID of the dynamic feature from which the track was derived. The result will be used as the ID for the new dynamic feature containing the track. All the remaining properties on the track's dynamic feature will be copied from the most recently received dynamic feature belonging to the track.

resubmit

Either "true" or "false" indicating whether the original dynamic feature should be submitted to SpatialRules (true) or it should be dropped (false) and only the resulting tracks should be submitted.

min

Is either an integer value specifying the minimum number of locations that must be in the track or a timespan specifying the minimum time difference between the most recent location and the oldest location in the history before a track can be made.

max

Is either an integer value specifying the maximum number of locations that can be in the track or a timespan specifying the maximum time difference between the most recent and the oldest locations in the history that can be included in the track.

feature

Is a feature expression to restrict track construction to only those dynamic features that meet the specified criteria.

The example below directs SpatialRules to create tracks for any dynamic feature that has an attribute "Restrictions" with a value of "HAZMAT". Those dynamic features will not be submitted to SpatialRules, only their tracks. The tracks must have a minimum of two locations but not more than ten:

(makeTrack "HAZMAT-10", false,
    (int "2"), (int "10"),
    (feature (eq (property "Restrictions"), "HAZMAT")))

This example changes the one above to say that there must be at least 10 minutes worth of locations in a track, but not more than 30 minutes worth:

(makeTrack "HAZMAT-30-Minutes", false,
    (minutes "10"), (minutes "30"),
    (feature (eq (property "Restrictions"), "HAZMAT")))

A.42. multiline

Defines a multi-line-string geometry.

(multiline <line>[, <line>]*)

where the line arguments are any combination of lines.

For example:

(multiline 
    (line "0.0,0.0 1.0,1.0 2.0,2.0 3.0,3.0 4.0,4.0"),
    (line "0.0,1.0 1.0,2.0"))

A.43. multipoint

Defines a multipoint geometry.

(multipoint <point>[, <point>]*)

where the point arguments are any combination of points.

For example:

(multipoint 
    (point "1.0,2.1"),
    (point "4.1,1.0"),
    (point "0.0,0.0"))

A.44. multipolygon

Defines a multipolygon geometry.

(multipolygon <polygon>[, <polygon>]*)

where the polygon arguments are any combination of polygons that meet the constraints of a valid multipolygon.

For example:

(multipolygon 
  (polygon 
    (ring "-93.12,45.0 -93.04,45.0 -93.04,44.9 -93.15,44.9 -93.16,44.97 -93.12,45.0")),
  (polygon 
    (ring "-93.3,45.0 -93.17,45.02 -93.2,44.909 -93.33,44.893 -93.36,44.956 -93.3,45.0"),
    (ring "-93.31,44.95 -93.32,44.94 -93.32,44.939 -93.3,44.946 -93.31,44.95"),
    (ring "-93.31,44.926 -93.313,44.91 -93.297,44.925 -93.31,44.926")))

A.45. nOf

A boolean n-ary expression that returns true when the specified number of child expressions return true.

(nOf "all"|"<count>", <boolean expression> [, <boolean expression>]*)

where:

all

Indicates that all expressions must be true.

count

Is an integer specifying how many of the child boolean expressions must be true for the nOf to be true. The value must be greater than 0 and less than or equal to the number of children.

boolean expression

Any boolean expression except expression.

Specifying "1" for the count is equivalent to putting all of the child expressions in or expressions. Specifying "all" for the count is equivalent to putting all of the child expressions in and expressions.

For example, if only one of a set of conditions needs to be met:

(nOf "1",
  (eq (property "LEVEL"), "YELLOW"),
  (eq (property "LEVEL"), "ORANGE"),
  (eq (property "LEVEL"), "RED"))

Or if all of the conditions must be met:

(nOf "all",
  (eq (property "type"), "TRUCK"),
  (eq (property "Restrictions"), "HAZMAT"),
  (eq (property "Origin"), "Cuba"))

nOf is most useful in cases where more than one condition must be true, but not all. In this example any 2 of the 3 conditions can result in true:

(nOf "2",
  (eq (property "Material"), "Chlorine"),
  (eq (property "Material"), "Fluorine"),
  (eq (property "Material"), "Anhydrous Ammonia"))

A.46. not

Negates its child boolean expression.

(not <expression>)
(not (eq (property "/Truck/Restrictions"), "HAZMAT"))

A.47. or

A boolean expression that returns true if one of its two child expressions returns true:

(or <boolean expression>, <boolean expression>)

where boolean expression is any boolean expression except expression.

For example:

(or
  (eq (property "/Truck/Restrictions"), "HAZMAT"),
  (eq (property "LEVEL"), "RED"))

A.48. overlaps

Returns true if a dynamic feature overlaps (see Section C.2.5, “Overlaps”) a target feature.

(overlaps <feature>|<featureRef>|<featureSetRef>)

where:

feature

Is a dynamic feature selector expression. See Section A.24, “feature”.

featureRef

Is a reference to a reference feature. See Section A.25, “featureRef”.

featureSetRef

Is a reference to a reference feature set. See Section A.27, “featureSetRef”. The subject dynamic feature only needs to be overlap one of the features in the feature set.

Overlaps a reference feature:

(overlaps (featureRef "AOI 2"))

Overlaps a dynamic feature:

(overlaps (feature
  (gt
    (property "Contamination-Level"),
    (variableRef "CurrentLevel"))))

A.49. period

Defines a time period for an interval or schedule.

(period "<name>", (date "<start>"), (date "<end>"))

where:

name

Is a unique identifier for the period.

start

Is the starting time for a fixed, one-time interval using a date string as described in Section A.66.6, “date”.

end

Is the end time for a fixed, one-time interval using a date string as described in Section A.66.6, “date”.

The second form

(period "<name>", (recurringTime <start>, (recurringTime <end>))

where:

name

Is a unique identifier for the period.

start

Is the starting time for a recurring time period as described in Section A.54, “recurringTime”.

end

Is the end time for a recurring time period as described in Section A.54, “recurringTime”.

For example, to create a time interval with fixed start and end times:

(period "fixed-period",
  (date "2008-02-13 14:34:09.781 CST"),
  (date "2008-02-13 21:34:09.781 CST"))

Or, to create a schedule for every Saturday through Sunday:

(period "Weekend",
  (recurringTime "0", "0", "7", null, null),
  (recurringTime "59", "23", "1", null, null))

A.50. periodRef

Denotes a reference (by name) to a period in the rule repository.

(periodRef "<period name>")

For example:

(expression "equipment left a construction site on a weekend",
  (and
    (during (periodRef "Weekend"))
    (and
      (fragmentRef "equipmentType"),
      (exits (featureSetRef "fs-construction-site"))
    )
  )
)

A.51. point

Defines a point geometry.

(point "<lon>,<lat>")

where:

lon

The longitude in decimal degrees as an easting, i.e., longitudes east of the Prime Meridian are positive; longitudes west are negative.

lat

The latitude in decimal degrees as a northing, i.e., latitudes north of the Equator are positive; latitudes south are negative.

[Note]

All geometry coordinates in SpatialRules must be in the CRS defined in Appendix B.3 of [wms-spec].

For example:

(point "-93.27833,44.98167")

A.52. polygon

Defines a polygon geometry.

(polygon <ring>[, <ring>]*)

where the first ring is the exterior boundary of the polygon and all other rings are holes.

For example, a polygon with just an exterior boundary:

(polygon 
  (ring "-93.3,45.0 -93.17,45.02 -93.2,44.909 -93.33,44.893 -93.36,44.956 -93.3,45.0"))

And a polygon with two holes:

(polygon 
  (ring "-93.3,45.0 -93.17,45.02 -93.2,44.909 -93.33,44.893 -93.36,44.956 -93.3,45.0"),
  (ring "-93.31,44.95 -93.32,44.94 -93.32,44.939 -93.3,44.946 -93.31,44.95"),
  (ring "-93.31,44.926 -93.313,44.91 -93.297,44.925 -93.31,44.926"))

A.53. property

A value expression that retrieves the value of an attribute from a dynamic feature.

(property "<property path>")

where property path is an XPath-like expression to reference the feature's properties. There

Keywords "id" and "type" may be specified to reference the ID and type values of a dynamic feature.

Get the feature's type:

(property "type")

Get the value of the "Contamination-Level" attribute from all dynamic features of type "Zone":

(property "/Zone/Contamination-Level")

Get the value of the "Contamination-Level" attribute from all dynamic features:

(property "Contamination-Level")

Get the feature's ID:

(property "id")

A.54. recurringTime

Specifies the repeating aspects of a time period.

(recurringTime "<minute>", "<hour>", "<day-of-week>",
               "<day-of-month>", "<month-of-year>")

where:

minute

The minute of the hour (0-59).

hour

The hour of the day using a 24-hour clock (0–23).

day-of-week

The day of the week as an integer from 1–7.

day-of-month

The day of the month (1–31).

month-of-year

The month of the year as an integer from 0–11.

For example, to specify a recurring time that occurs every half hour only on Tuesdays:

(recurringTime "30", null, "3", null, null)

A.55. referenceFeature

Defines a feature to be used as a reference feature.

(referenceFeature "<id>", "<type>", "<name>", <geometry>[,
  (attr "<key>", "<value>")]*)

where:

id

Is a unique string identifier for the feature.

type

Is a string specifying the feature's type.

name

Is a string specifying the feature's name.

geometry

Is any supported geometry.

key

Is a string key for an attribute.

value

Is the value for the attribute (use the datatypes defined in Section A.66, “Data Types”).

For example:

(referenceFeature "stadium.1", "stadium", "Target Field",
  (point "-93.27833,44.98167"),
  (attr "bestSection", "3"),
  (attr "claimToFame", "Home of the Twins"))

A.56. regex

See Section A.36, “isLike”.

A.57. ring

Defines a ring geometry.

(ring "<lon>,<lat> [<lon>,<lat>]+")

where:

lon

The longitude in decimal degrees as an easting, i.e., longitudes east of the Prime Meridian are positive; longitudes west are negative.

lat

The latitude in decimal degrees as a northing, i.e., latitudes north of the Equator are positive; latitudes south are negative.

[Note]

All geometry coordinates in SpatialRules must be in the CRS defined in Appendix B.3 of [wms-spec].

For example:

(ring "0.0,0.0 5.5,0.0 5.6,1.1 0.0,2.32 0.0,0.0")

A.58. set

An unordered collection of unique values (duplicates will be dropped if present).

(set (<value>[, <value>]*]?)

where value is a literal value using one of the data types listed in Section A.66, “Data Types”.

A.59. stateTransition

A boolean expression that steps through its children, evaluating only the "current" child until the child evaluates to true. Once a child evaluates to true, the next (or first if the current child was the last in the list) child in the list is selected as the "current" child.

(stateTransition (transition "<name>", <boolean expression>) [,
                 (transition "<name>", <boolean expression>)]+)

Each transition expression is defined by the keyword "transition", an identifier, and a complete rule, which is a boolean expression.

(stateTransition
  (transition "enterA", (within (feature (eq
    (property "type"),
    "Zone_A")))),
  (transition "enterB", (within (feature (eq
    (property "type"),
    "Zone_B")))),
  (transition "exitArea", (exits (featureRef "Area_C"))))

A.60. transition

See Section A.59, “stateTransition”.

A.61. true

Used as an expression that always returns True.

(feature true)

A.62. variable

Defines a variable with an initial value.

(variable "<name>", <literal>|<data type>)

Create a variable with an initial string value:

(variable "THREAT-LEVEL", "GREEN")

Create a variable with an initial double value:

(variable "threshold", (double "16.75"))

A.63. variableRef

Denotes a reference (by name) to a variable in the rule repository.

(variableRef "<variable name>")

The current value of the "THREAT-LEVEL" variable is "ORANGE" or "RED":

(or
  (eq (variableRef "THREAT-LEVEL", "ORANGE")),
  (eq (variableRef "THREAT-LEVEL", "RED"))
)

A.64. within

Returns true if a dynamic feature is completely contained (see Section C.2.3, “Contains/Within”) by a target feature.

(within <feature>|<featureRef>|<featureSetRef>)

where:

feature

Is a dynamic feature selector expression. See Section A.24, “feature”.

featureRef

Is a reference to a reference feature. See Section A.25, “featureRef”.

featureSetRef

Is a reference to a reference feature set. See Section A.27, “featureSetRef”. The subject dynamic feature only needs to be contained in one of the features in the feature set.

Within the bounds of a reference feature:

(within (featureRef "state-MN"))

Within the bounds of a dynamic feature:

(within (feature (eq (property "type"), "perimeter"))

A.65. Arithmetic Operators

SpatialRules expressions provide a number of operators for performing calculations to derive values during rule evaluation. For more definition see the Java documentation for the java.lang.Math class.

Arithmetic operators can take literal values, variables, properties, or other arithmetic operators as arguments. Arithmetic operators expect that their value arguments return a value of type java.lang.Number at runtime-they will not convert string values. You will get an exception if a non-number is returned.

A.65.1. Unary Operators

Unary operators take only one argument.

(<unary operator> <value>)

For example,

(sqrt (abs (variableRef "var")))

The following unary operators are supported:

abs

Absolute value.

sin

Sin of a value.

cos

Cosine of a value.

tan

Tangent of a value.

asin

Arc tangent of a value.

acos

Arc cosine of a value.

atan

Arc tangent of a value.

exp

Euler's number. Computes e to a power specified.

log

Logarithm of a value.

sqrt

Square root of a value.

ceil

Ceiling of a value.

floor

Floor of a value.

rint

Rounds a value expression to the nearest mathematical integer.

A.65.2. Binary Operators

Binary operators take only two arguments.

(<binary operator> <value>, <value>)

For example,

(mul (div (int "5"), (int "9")), (sub (property "temperature"), (int "32")))

The following binary operators are supported:

add

Adds two values.

sub

Subtracts two values.

mul

Multiplies two values.

div

Divides two values.

min

Computes the minimum of two values.

max

Computes the maximum of two values.

atan2

Converts the values of two expressions to the theta phase of polar coordinates (r, theta). This is computed by taking the arc tangent of right over left.

pow

Number to a power (exponent)

A.66. Data Types

Data types are essentially literals with a type name so that the string value can be converted to the appropriate data type when the RulesScript is parsed. Data types have the following general form:

(<type> "<value>")

The following data types are available:

A.66.1. char

Character data. Strings are left unconverted as a Java String. This is the default data type and does not need to be explicitly specified.

Example comparing a property to a literal string value:

(eq (property "/Truck/Restrictions"), (char "HAZMAT"))))

A.66.2. int

Integer numeric. Values are converted to a Java int. The range for an "int" value is (-231) to (231-1).

(int "5")

A.66.3. long

Integer numeric. Values are converted to a Java long. The range for a "long" value is (-263) to (263-1).

(long "5")

A.66.4. float

Floating point numeric. Values are converted internally to a Java float. Java float values are defined by the 64-bit IEEE 754 floating-point numbers.

(float "5.5")

A.66.5. double

Floating point numeric. Values are converted internally to a Java double. Java double values are defined by the 64-bit IEEE 754 floating-point numbers.

(double "5.5")

A.66.6. date

Dates and times. Dates are converted internally to a Java Date and have the following string representation.

(date "yyyy-MM-dd HH:mm:ss:SSS z")

Example:

(date "2006-02-28 18:35:00:000 CDT")

A.67. Distances

Distances have the following general form:

(<units> "<double-value>"[, "<distance-type>"])

The distance-type indicates how the measurement is performed. The following distance types are available: greatCircle and euclidean. If no distance-type is specified, greatCircle is used.

The following distance units are available:

m

Meters

km

Kilometers

ft

Feet

mi

Miles

nmi

Nautical Miles

deg

Degree Angle

A.68. Time Spans

Time spans have the following general form:

(<units> "<long-value>")

The following time span units are available:

days

Days

hours

Hours

minutes

Minutes

seconds

Seconds

milliseconds

Milliseconds

microseconds

Microseconds

nanoseconds

Nanoseconds

Appendix B. Utilities

There are a number of utilities available in the distribution that can assist with maintaining and setting up rules.

B.1. Command-line tools

These tools are available as command-line scripts to be run directly from a shell. There are also corresponding Java classes that can be used to perform the same functions programmatically. The Java classes are documented in the API documentation.

All of the command-line scripts (located in the bin directory) use a common script named launch.[cmd|sh]. The launcher script contains centralizes all of the classpath setup, evironment handling, etc. For example, the following is a line taken from the submit script:

call "%HERE%\launch.cmd" com.objectfx.rules.tools.SubmitDynamicFeatures %*

Each command has a unique set of command line parameters. The parameters for each are defined below.

B.1.1. import

The import command is used to import reference reatures from a file or URL. Features can automatically be added to a feature set by specifying a name. A number of data formats are supported such as KML, KMZ, GeoRSS, and Shapefiles.

The import command has the following general form:

import [-featureSet name] -format type [-overwrite] [-prefixIds] -properties filename -source filename|url

The options are:

-featureSet <name>

Specifying a featureSet name will cause all features loaded to also be added to a featureSet of the name specified.

-format <type>

Import data format. Valid values are kml, kmz, georss, shapefile.

-overwrite

If specified, existing versions of the feature will be overwritten.

-prefixIds

If specified, feature IDs will be prefixed with "<feature type>-".

-properties <filename>

Properties file to use.

-source <filename|url>

Input source filename or URL.

-help

Display usage.

The corresponding Java class for this command is com.objectfx.rules.tools.ImportReferenceFeatures.

B.1.2. submit

The submit command is used to submit data for evaluation to a SpatialRules server. The data can be provided in any number of formats including KML, KMZ, Shapefile and GeoRSS.

The submit command has the following general form:

submit -format type -properties filename -source filename|url

The options are:

-format <type>

Import data format. Valid values are kml, kmz, georss, shapefile.

-properties <filename>

Properties file to use.

-source <filename|url>

Input source filename or URL.

-help

Display usage.

The corresponding Java class for this command is com.objectfx.rules.tools.SubmitDynamicFeatures.

B.1.3. dbadmin

The dbadmin command is used to manage the RulesDatabase. This command provides a way to import and export the entire contents of a RulesDatabase to a text form. Databases can be created and emptied (cleaned) as well.

The dbadmin command has the following general form:

dbadmin { -clean | -create | -import filename [-overwrite] | -export filename [-xf] | -help }

The options are:

-clean

Removes all data from the database.

-create

Creates a new empty database.

-export <filename>

Export the entire contents of a database to a text format.

-xf

If specified, export everything except for reference features.

-import <filename>

Import items from a text format.

-overwrite

If specified, existing items will be overwritten by any with the same ID.

-help

Display usage.

The corresponding Java class for this command is com.objectfx.rules.tools.DbAdmin.

B.1.4. spatialrules

Launches the server provided by ObjectFX.

The spatialrules command has the following options:

-h,-help

Prints usage information.

-s, -service

Runs spatial rules without console exit option.

[Note]

The source code for the SpatialRules server is provided in the examples distribution. This is useful for modifying the server as necessary.

B.2. Cron

Cron (com.objectfx.rules.cron.Cron) is a simple scheduling utility provided by SpatialRules for implementing services that periodically perform some task. The most common use of Cron is to periodically scan the indexes of Rules Service to remove any data that is considered out-of-date (see Section 3.5, “Aging Data”), but it could also be used to monitor a drop-box, e.g., a directory where inbound files are written, containing dynamic features to be submitted.

B.2.1. Starting Cron

There is only one method for starting up Cron: startup(). When startup() is called, Cron checks to see if it has any jobs that need to be scheduled for execution. If there are, it creates the schedule for those jobs and then begins executing the schedule.

To start up Cron:

Cron.getInstance().startup();

B.2.2. Adding Jobs

Cron jobs are created by implementing the Callable (java.util.concurrent.Callable) interface and then submitting the implementation to Cron with one of the addJob() methods. When you submit a callable to Cron, it is associated with three properties used to create jobs:

job name

A unique name for the job. If you attempt to add a callable with a duplicate name an exception will be thrown.

group name

Group names are used to limit the concurrency of jobs—no two jobs from the same group can be executing at the same time. Before submitting a job for execution, Cron will ensure that no job from the same group is currently executing. if one is still in progress, it will cancel the job that it was about to submit.

Group names are also used to aggregate the results from jobs. The results from all jobs within the group are put in one collection that is retrieved by the group name (see below for details).

schedule

A schedule can be either a fixed time using an instance of Date (java.util.Date), a repeating interval using an instance of TimeSpan (com.objectfx.rules.TimeSpan), or a recurring time using an instance of RecurringTime (com.objectfx.rules.time.RecurringTime).

The following is an example of a simple Cron job that writes a message to the console every 10 seconds.

Callable callable = new Callable(){
  public Object call() throws Exception {
    System.out.println("Called at " + new Date());
    return null;
  }
};

Cron cron = Cron.getInstance();
cron.addJob("Test-Group", "My-Job", callable, new TimeSpan(10, TimeUnit.SECONDS));
cron.startup();

B.2.3. Removing Jobs

To remove a job, just call removeJob(String jobName). This method returns true if a job with the specified name exists and is removed, otherwise it returns false.

Cron.getInstance().removeJob("My-Job");

B.2.4. Getting Results

Whenever a job is scheduled for execution, a Future (java.util.concurrent.Future) is created for it and added to a collection so that it can be retrieved asynchronously. The Futures are added to FIFO queues—one for each group—with a limit of 200 Futures on each to prevent them from growing indefinitely.

To retrieve the collection of all completed Futures for a group, call getResults(String groupName). Any Futures for that group that have not yet completed will be left in the queue.

For example, to iterate over the results and collect them up:

List<MyJobResult> results = new ArrayList<MyJobResult>()
for (Future future : Cron.getInstance().getResults("MyGroupName")) {
   if (!future.isCancelled()) {
      try {
         list.add((MyJobResult) future.get());
      } catch (final Exception e) {
         // Save results that had exceptions also.
         list.add(new MyJobResult(e));
      }
   }
}

B.2.5. Stopping Cron

There are two methods for shutting down Cron:

  • The shutdown() method will wait up to ten seconds for any in-progress jobs to complete.

  • The shutdown(long timeout) method will wait up to the specified number of milliseconds for any in-progress jobs to complete.

For example, to have Cron wait up to five seconds for any currently executing jobs:

Cron.getInstance().shutdown(5000);

When you call one of the shutdown methods, Cron stops queuing jobs for execution and then waits for the selected timeout period. If it reaches the end of the timeout period and not all of the jobs have completed, Cron will interrupt all of the still-executing threads and then return from the shutdown call.

To ensure a safe shutdown, any jobs that cannot tolerate an unexpected shutdown should either include a method for you to signal a shutdown or they should be able to detect when Cron interrupts the thread in which they are executing. The threads that Cron uses to execute tasks are all daemon threads. When the JVM exits, all Cron threads will be terminated, regardless of their current state.

Appendix C. Geometries

C.1. Geometry Object Model

Geometries provide a way to define the geographic characteristics of a feature, relating it to the earth. The geometry model is based on [spatial-schema] with support for points, line strings, polygons, and collections. Geometries are two-dimensional, consist of X,Y coordinate pairs, and are associated with a Coordinate Reference System, which describes the coordinate space in which the geometry is defined. The following sections describe the geometry object model and details pertaining to each geometry type.

C.1.1. Class hierarchy

The class diagram below depicts the geometry class hierarchy and the relationships between the geometry types. The following sections detail each of the classes shown in the diagram.

Figure C.1. Geometry Class Hierarchy

Geometry Class Hierarchy

C.1.2. Geometry

The geometry interface (com.objectfx.geometry.Geometry) is the root of the class hierarchy. It defines properties and methods common to all geometry implementations. These are listed below:

Coordinate Reference System

A geometry's Coordinate Reference System (CRS) describes the coordinate space in which the geometry's coordinates are defined. The CRS may be queries using the getCoordinateReferenceSystem() method. The constant Geometry.WGS84 is defined on the Geometry interface and is used as the default Coordinate Reference System if one is not supplied when constructing a geometry. This is a geographic Coordinate Reference System based on the WGS 84 ellipsoid with longitude as the X-axis and latitude as the Y-axis.

dimensionality

A geometry may have a dimension of 0, 1, or 2. 0-dimensional geometries have no length or area (e.g. a point), 1- dimensional geometries have a length (e.g. a line string), and 2-dimensional geometries have an area (e.g. a polygon). The dimension of a geometry may be queried using the dimension() method.

validity

The validity of a geometry describes how well the coordinates in a geometry fit the rules set forth in section 6.1 of the [simple-feature-spec] document. The type of geometry dictates the validity rules; refer to the specification and the geometry sections below for more details on the validity rules for each geometry type.

Geometry validity directly affects how a geometry interacts with other geometries and its behavior within the system; results are indeterminate if a geometry is invalid. Validity may be evaluated for a geometry using the isValid() method. It is your responsibility to ensure that all geometries are valid; the isValid() method must be invoked from application code, it is not invoked in the normal flow of geometry interactions.

centroid

A geometry's centroid is its mathematical centroid, represented by a point geometry. The result point is not guaranteed to be on the object. This property may be queried using the cenroid() method.

For heterogeneous collections of primitive geometries, calculation of the centroid only takes into account those of the largest dimension. For example, when calculating the centroid of a collection including both points and polygons, the average is taken weighted only by area. Since points have no area they do not contribute to the result.

envelope

The envelope of a geometry is its minimum bounding rectangle (MBR), represented as an Envelope geometry. This is the region spanning the minimum and maximum values of the X and Y values contained in the geometry's coordinates. A geometry collection associated with a Coordinate Reference System which has an X-axis that is able to wraparound (e.g. a geographic Coordinate Reference System) may produce an envelope which spans the anti-meridian. The envelope of a geometry may be queried using the getEnvelope() method.

spatial relations

All geometries define the following set of spatial relation methods:

  • intersects

  • disjoint

  • contains/within

  • covers/coveredBy

  • overlaps

These spatial relations are discussed in more detail in Section C.2, “Spatial Relations”.

distance

Distance between geometries can be evaluated using both great circle and euclidean methods. Distance is calculated by finding the two closest points on the geometries being compared, which are not necessarily supplied coordinate values, and calculating the distance between them based on the Coordinate Reference System being used.

For a geometry with a geographic Coordinate Reference System, the distance() method calculates the great-circle distance, while the euclideanDistance() method calculates the euclidean distance in between two points in 3-dimensional space (i.e. through the earth). For a geometry with a projected Coordinate Reference System distance both the distance() and euclideanDistance() methods calculate distance using the euclidean method.

C.1.3. Point

A point (com.objectfx.geometry.Point) is a zero-dimensional object, consisting of an X and Y coordinate value, representing a single location in space. Points can be used to define features such as vehicle locations, landmarks, and hazardous waste sites.

A point's boundary is the empty set. Point geometries have no validity constraints.

The following example illustrates how an instance of a point is constructed in the default Coordinate Reference System (WGS84):

Point pt1 = new Point2d(34, 46);

C.1.4. Line String

A line string (com.objectfx.geometry.LineString) is a one-dimensional sequence of two or more points which define a path. Line strings can be used to define features such as highways, streams, or the path of a moving object.

The boundary of a line string is its two endpoints. The interior of a line string is defined as the connected set of segments which lie between the endpoints. A line string must have at least 2 distinct points. A line string containing points that are all topologically equivalent is invalid.

The following example illustrates how an instance of a line string is constructed in the default Coordinate Reference System (WGS84):

double[] xs = new double[] { -100, -95, -92 };
double[] ys = new double[] { 35, 39, 32 };
LineString lineString = new LineString2d(xs, ys);

C.1.5. Linear Ring

A linear ring (com.objectfx.geometry.LinearRing) is a type of line string which is closed and simple. A linear ring is closed because its start point is equal to its end point, and it is simple because it does not pass through the same point more than once. Linear rings are most often used to describe the exterior and interior boundaries of a polygon. Linear rings do not contain any area; a polygon should be used if the intent is to describe an area of space.

A linear ring's boundary is the empty set and being closed, the interior of a linear ring is continuous.

The figure below depicts a valid linear ring.

Figure C.2. Valid Linear Ring

Valid Linear Ring

The following figure shows examples of invalid linear rings: (A) shows a linear ring which self intersects. (B) shows a linear ring with a spike, a section which doubles back on itself. (C) shows a linear ring which intersects itself at a point.

Figure C.3. Invalid Linear Rings

Invalid Linear Rings

The following example illustrates how an instance of a linear ring is constructed in the default Coordinate Reference System (WGS84):

double[] xs = new double[] { -100, -100, -95, -95, -100 };
double[] ys = new double[] { 35, 40, 40, 35, 35 };
LinearRing linearRing = new LinearRing2d(xs, ys);

Note that the last coordinate in a linear ring is not required during construction. If omitted, a closing x,y coordinate pair equivalent to the first will be added to the input coordinates.

C.1.6. Polygon

A polygon (com.objectfx.geometry.Polygon) is a two-dimensional surface stored as a sequence of points defining its exterior bounding ring and 0 or more interior rings defining its holes. A polygon may be used to describe features that have an area, such as political boundaries, land masses, or areas of interest.

The boundary of a polygon is defined by the set of linear rings making up its exterior and interior boundaries. A polygon's interior is defined by the area spanning between, but not including, its exterior and interior rings. In addition to the validity constraints imposed by its set of linear rings, the interior rings of a polygon may only intersect the exterior or other interior rings at a single tangent point. They cannot cross nor share an edge.

The figure below depicts valid polygons. (A) shows a polygon with no interior rings. (B) shows a polygon with two interior rings. (C) shows a polygon with three interior rings, one touching the exterior ring at a tangent point, and two others intersecting at a tangent point.

Figure C.4. Valid Polygons

Valid Polygons

The figure below depicts invalid polygons. (A) shows a polygon with an interior ring intersecting at more than one tangent point. (B) shows a polygon with interior rings intersecting at more than one tangent point. (C) shows a polygon with an interior ring that is not completely enclosed by the exterior ring.

Figure C.5. Invalid Polygons

Invalid Polygons

The following example illustrates how an instance of a polygon is constructed, with and without interior rings in the default Coordinate Reference System (WGS84):

double[] exteriorXs = new double[] { -100, -100, -90, -90, -100 };
double[] exteriorYs = new double[] { 30, 40, 40, 30, 30 };
LinearRing exteriorRing = new LinearRing2d(exteriorXs, exteriorYs);
Polygon noHoles = new Polygon2d(exteriorRing);

double[] interiorXs = new double[] { -99, -99, -97, -97, -99 };
double[] interiorYs = new double[] { 37, 38, 38, 37, 37 };
LinearRing interiorRing = new LinearRing2d(interiorXs, interiorYs);
LinearRing[] interiorRings = new LinearRing[] { interiorRing };
Polygon withHoles = new Polygon2d(exteriorRing, interiorRings);

C.1.7. Multi-Point

A multi-point (com.objectfx.geometry.MultiPoint) is a zero-dimensional geometry consisting of a collection of point geometries that are not connected or ordered in any way. All member points must be of the same Coordinate Reference System. Multi-point geometries can be used to describe features such as disease outbreaks or traffic incidents locations in a particular area.

The boundary of an multi-point is the empty-set. Multi-point geometries have no validity constraints; member points may be disjoint or overlapping.

The following example illustrates the construction of a multi-point geometry in the default Coordinate Reference System (WGS84):

Point pt1 = new Point2d(34, 46);
Point pt2 = new Point2d(25, 54);
Point pt3 = new Point2d(29, 41);

Point[] points = new Point[] { pt1, pt2, pt3 };
MultiPoint multiPoint = new MultiPoint2d(points);

C.1.8. Multi-LineString

A multi-line string (com.objectfx.geometry.MultiLineString) is one-dimensional geometry consisting of a collection of line string geometries, which must all be of the same Coordinate Reference System. If all member geometries have endpoints which intersect, the boundary is the empty set. Multi-line strings can be used to describe such features as highway networks or river deltas.

The boundary of an multi-line string is considered to be any endpoints of member line strings which do not intersect other member line strings. Member line strings may be disjoint or overlapping. Multi-line string geometries must contain valid line strings in order to be considered valid.

The following example illustrates the construction of a multi-line string geometry in the default Coordinate Reference System (WGS84):

LineString ls1 = new LineString2d(
      new double[] { 10, 11, 12 },
      new double[] { 13, 14, 15 });
LineString ls2 = new LineString2d(
      new double[] { 7, 6, 5 },
      new double[] { 4, 3, 2 });

LineString[] lineStrings = new LineString[] { ls1, ls2 };
MultiLineString multiLineString = new MultiLineString2d(lineStrings);

C.1.9. Multi-Polygon

A multi-polygon (com.objectfx.geometry.MultiPolygon) is a 2-dimensional geometry consisting of a collection of polygon geometries. All member polygons must be of the same Coordinate Reference System. The boundary of a multi-polygon consists of its member polygon's exterior and interior rings. The interior consists of the combined interiors of its member polygons. Multi-polygons can be used to describe features such as non-contiguous land masses (e.g. Hawaii) or political boundaries.

Multi-polygons must contain valid polygons in order to be considered valid. In addition, the boundaries of its member polygons may only intersect at a finite number of points. This means that members may not share an edge, as they would intersect at a continuous number of points.

The figure depicts three examples of valid multi-polygons. (A) shows a multi-polygon with two member polygons. (B) shows a multi-polygon with two member polygons intersecting at a finite number of points. (C) shows a polygon with an interior ring nested within the interior ring of another polygon.

Figure C.6. Valid Multi-Polygons

Valid Multi-Polygons

The following figure show examples of invalid multi-polygons: (A) shows a multi-polygon with overlapping member polygons. (B) shows a multi-polygon with one member connected by a segment.

Figure C.7. Invalid Multi-Polygons

Invalid Multi-Polygons

The following example illustrates the construction of a multi-polygon in the default Coordinate Reference System (WGS84):

LinearRing poly1ExteriorRing = new LinearRing2d(
      new double[] { -100, -100, -90, -90, -100 },
      new double[] { 30, 40, 40, 30, 30 });
Polygon polygon1 = new Polygon2d(poly1ExteriorRing);

LinearRing poly2ExteriorRing = new LinearRing2d(
      new double[] { 50, 50, 60, 60, 50 }, 
      new double[] { 10, 20, 20, 10, 10 });
LinearRing poly2InteriorRing = new LinearRing2d(
      new double[] { 52, 52, 58, 58, 52 }, 
      new double[] { 12, 18, 18, 12, 12 });
LinearRing[] poly2InteriorRings = new LinearRing[] { poly2InteriorRing };
Polygon polygon2 = new Polygon2d(poly2ExteriorRing, poly2InteriorRings);

Polygon[] memberPolygons = new Polygon[] { polygon1, polygon2 };
MultiPolygon multiPolygon = new MultiPolygon2d(memberPolygons);

C.1.10. Geometry Collection

A geometry collection (com.objectfx.geometry.GeometryCollection) is a heterogeneous collection of geometries. Geometry collections may contain other geometry collections. All member geometries in a collection must be associated with the same Coordinate Reference System. Geometry collections are valid only if all their member geometries are valid.

The following example illustrates the construction of a geometry collection in the default Coordinate Reference System (WGS84):

Point point = new Point2d(54, 23);
LineString lineString = new LineString2d(
      new double[] { 7, 6, 5 },
      new double[] { 4, 3, 2 });
LinearRing polyExteriorRing = new LinearRing2d(
      new double[] { -100, -100, -90, -90, -100 },
      new double[] { 30, 40, 40, 30, 30 });
Polygon polygon = new Polygon2d(polyExteriorRing);

Geometry[] memberGeometries = new Geometry[] { point, lineString, polygon};
GeometryCollection geometryCollection = new GeometryCollection2d(memberGeometries);

C.1.11. Envelope

An envelope (com.objectfx.geometry.Envelope) is a two dimensional geometry specified by two corners, the lower left and upper right. Envelopes are used to represent the minimum bounding rectangle (MBR) of a geometry, per Geometry.getEnvelope(), and also as search geometries when querying data for map image generation and simple area searches. Envelopes enforce that the minimum X ordinate is <= the maximum X ordinate and the minimum Y ordinate is <= the maximum Y value.

The following example illustrates how to construct an Envelope geometry in the default Coordinate Reference System (WGS84):

double minX = -105.0;
double minY = 25.0;
double maxX = -82.0;
double maxY = 51.0;

Envelope envelope = new Envelope(minX, minY, maxX, maxY);

An alternative way of constructing an envelope is to use the factory method Envelope.createEnvelope(). The following example shows how to create an envelope using the createEnvelope() method in the WGS84 Coordinate Reference System:

Envelope envelope = Envelope.createEnvelope(minX, minY, maxX, maxY, Geometry.WGS84);

The createEnvelope() method also allows construction of an envelope which spans the anti-meridian, provided that the Coordinate Reference System has a continuous X-axis which can wraparound, as with a geographic Coordinate Reference System. By specifying a maximum X value that is > the minimum X value, it is inferred that the envelope intends to span the anti-meridian. In these cases a wrapped envelope will be created. Wrapped envelopes are discussed in the next section.

C.1.12. Wrapped Envelope

A wrapped envelope (com.objectfx.geometry.WrappedEnvelope) is a specialization of an envelope, which contains an eastern and western envelope pair sharing a boundary on the anti-meridian. This type of envelope is most commonly used in queries when the area of interest spans the anti-meridian, or as the envelope of a geometry collection where the minimum bounding rectangle's shortest longitudinal path lies across the anti-meridian. Further details about dealing with geometries which span the anti-meridian can be found in Section C.4, “Boundary Cases”.

Wrapped envelopes may only be created using the Envelope.createEnvelope() factory method, specifying a specifying a maximum X value that is > the minimum X value. The following example shows the creation of a wrapped envelope in the WGS84 Coordinate Reference System which spans the anti-meridian:

double minX = 160.0;
double minY = 25.0;
double maxX = -170.0;
double maxY = 51.0;

// note that minX > maxX
WrappedEnvelope envelope = 
   (WrappedEnvelope) Envelope.createEnvelope(minX, minY, maxX, maxY, Geometry.WGS84);

C.2. Spatial Relations

The spatial relationship between geometry objects can be determined by a set of methods inherent on each geometry type. The relations are based on the relation operators and the Dimensionally Extended 9 Intersection Model (DE-9IM) developed by Clementini, et al. laid forth in section 6.1.15 of [simple-feature-spec]. Implemented relations include: intersects, disjoint, contains, within, and overlaps. A covers relation is added in addition to the relations defined in the [simple-feature-spec]. The touches and crosses relationships are currently unsupported.

Each of the supported relation methods is described in the following sections. For a more thorough treatment of spatial relations, refer to the [simple-feature-spec]. To frame the overview, we need to cover a couple key ideas. First, the [simple-feature-spec] categorizes a geometry's points as belonging to either the interior, boundary or exterior. The boundary consists of points or lines that separate the interior from the exterior. The boundary of a point is the empty set. The boundary of a line consists of its end points. The boundary of a polygon is the line that describes its perimeter. The interior consists of points that are in the geometry but not on its boundary, and the exterior consists of those points that are not in the geometry's interior or boundary. Secondly, the OGC specification categorizes geometry by dimension. Points have a dimension of 0. Lines have a dimension of 1, and polygons have a dimension of 2. When a relation is computed between two geoemtries, we can think of the result as a geometry with dimensions of -1 (no relation), 0, 1, or 2.

The following sections describe the supported spatial relations along with tables and figures used to describe the relationships. The possible values found in the tables and their meanings are listed below:

  • T means an intersection must exist

  • F means an intersection must not exist.

  • * means it does not matter if an intersection exists or not. Applicable to the intersection geometry dimensions of -1, 0, 1, or 2;

  • 0 means an intersection must exist and the intersection geometry must have a dimension of 0 (a point).

  • 1 means an intersection must exist and the intersection geometry must have a dimension of 1 (a line string).

  • 2 means an intersection must exist and the intersection geometry must have a dimension of 2 (a polygon).

C.2.1. Intersects

Geometries intersect with each other if their boundaries and/or interiors intersect. The following set of tables illustrates the possible intersects cases.

Geometry A intersects geometry B is TRUE if the interiors of A and B intersect.

IntersectsGeometry B
InteriorBoundaryExterior
Geometry AInteriorT**
Boundary***
Exterior***

Geometry A intersects geometry B is TRUE if the boundary points of A intersect with the boundary points of B.

IntersectsGeometry B
InteriorBoundaryExterior
Geometry AInterior*T*
Boundary***
Exterior***

Geometry A intersects geometry B is TRUE if the boundary points of A intersect with the interior of B.

IntersectsGeometry B
InteriorBoundaryExterior
Geometry AInterior***
BoundaryT**
Exterior***

Geometry A intersects geometry B is TRUE if the boundary points of A intersect with the boundary points of B.

IntersectsGeometry B
InteriorBoundaryExterior
Geometry AInterior***
Boundary*T*
Exterior***

C.2.2. Disjoint

Geometries are considered disjoint if their boundaries and interiors do not intersect. Disjoint is the exact opposite of intersect. As the following table illustrates, geometry A is disjoint from geometry B if there is no intersection between the interior and boundary of A and the interior and boundary of B.

DisjointGeometry B
InteriorBoundaryExterior
Geometry AInteriorFF*
BoundaryFF*
Exterior***

C.2.3. Contains/Within

A geometry contains another geometry if the interior and boundary of the comparison geometry is completely contained in the interior of the other geometry. Contains is the exact opposite of within; any geometry A containing geometry B means that B is within A. In the following table, geometry A contains geometry B if all of the interior of A intersects with the interior of B and there is no intersection between the exterior of A and the interior and boundary of B.

ContainsGeometry B
InteriorBoundaryExterior
Geometry AInteriorT**
Boundary***
ExteriorFF*

Figure C.8. Examples of Contains Relationship

Examples of Contains Relationship

A geometry is within another geometry if its interior and boundary are completely contained in the interior of the other geometry. The following table illustrates that geometry A is within geometry B if the interior of A intersects with the interior of B and there is no intersection between the interior and boundary of A with the exterior of B. Within is the exact opposite of contains.

WithinGeometry B
InteriorBoundaryExterior
Geometry AInteriorT*F
Boundary**F
Exterior***

C.2.4. Covers/Covered By

A geometry covers another geometry if it that geometry is completely contained in the interior or boundary of another geometry. Covers differs from contains in that the intersection of A's interior points with B's interior points can be a null set. For example, a point on a polygons boundary is covered by that polygon, but it is not contained by that polygon. The first set of tables below shows the patterns for the covers relation.

Geometry A covers geometry B is TRUE if the interiors of A and B intersect and there is no intersection between the exterior of A and the interior and boundary of B.

CoversGeometry B
InteriorBoundaryExterior
Geometry AInteriorT**
Boundary***
ExteriorFF*

Geometry A covers geometry B is TRUE if the interior of A intersects with the boundary of B and there is no intersection between the exterior of A and the interior and boundary of B. This is shown in the polygon - line and polygon - point examples in Figure C.9, “Examples of Covers Relationship”.

CoversGeometry B
InteriorBoundaryExterior
Geometry AInterior*T*
Boundary***
ExteriorFF*

Geometry A covers geometry B is TRUE if the boundary of A intersects the interior of B and there is no intersection between the exterior of A the interior and boundary of B. This is shown in the line - point example in Figure C.9, “Examples of Covers Relationship”.

CoversGeometry B
InteriorBoundaryExterior
Geometry AInterior***
BoundaryT**
ExteriorFF*

Geometry A covers geometry B is TRUE if the boundary of A intersects the boundary of B and there is no intersection between the exterior of A and the interior and boundary of B.

CoversGeometry B
InteriorBoundaryExterior
Geometry AInterior***
Boundary*T*
ExteriorFF*

Figure C.9. Examples of Covers Relationship

Examples of Covers Relationship

Geometry A covered by geometry B is TRUE if the interior of A intersects with the interior of B and there is no intersection between the interior and boundary of A and the exterior of B.

Covered ByGeometry B
InteriorBoundaryExterior
Geometry AInteriorT*F
Boundary**F
Exterior***

Geometry A covered by geometry B is TRUE if the interior of A intersects with the boundary of B and there is no intersection between the interior and boundary of A and the exterior of B.

Covered ByGeometry B
InteriorBoundaryExterior
Geometry AInterior*TF
Boundary**F
Exterior***

Geometry A covered by geometry B is TRUE if the boundary of A intersects with the interior of B and there is no intersection between the interior and boundary of A and the exterior of B.

Covered ByGeometry B
InteriorBoundaryExterior
Geometry AInterior**F
BoundaryT*F
Exterior***

Geometry A covered by geometry B is TRUE if the boundary of A intersects with the boundary of B and there is no intersection between the interior and boundary of A and the exterior of B.

Covered ByGeometry B
InteriorBoundaryExterior
Geometry AInterior**F
Boundary*TF
Exterior***

C.2.5. Overlaps

Overlaps only compares geometries of the same spatial dimension and checks that the intersection set of both geometries results in a different geometry of the same spatial dimension. For example, A overlaps B if the intersection of A and B's interior points is not an empty set and the intersection of A's interior points and B's exterior points is not an empty set and the intersection of B's interior points and A's exterior points is not an empty set.

The following table shows how relations of polygon to polygon, multi-point to multi-point, and multi-polygon to multi-polygon are interpreted. A overlaps B is TRUE if the interior and exterior of A intersects the interior and exterior of B. This is shown in the polygon - polygon example in Figure C.10, “Examples of Overlaps Relationship”.

OverlapsGeometry B
InteriorBoundaryExterior
Geometry AInteriorT*T
Boundary***
ExteriorT**

The following table shows how relations of line string to line string and multi-line string to multi-line string are interpreted. Geometry A overlaps geometry B if the interior of A intersects the interior of B as a 1-dimensional geometry (a line string), the exterior of A intersects the interior of B, and there is no intersection between the interior of A with the exterior of B. This is shown in the line - line example in Figure C.10, “Examples of Overlaps Relationship”. Overlaps is FALSE if the intersection of the interiors results in a 0-dimensional geometry (a point).

OverlapsGeometry B
InteriorBoundaryExterior
Geometry AInterior1*F
Boundary***
ExteriorT**

Figure C.10. Examples of Overlaps Relationship

Examples of Overlaps Relationship

C.3. 3D Geometries

SpatialRules supports a limited set of three-dimensional (3D) geometries called extruded geometries. An extruded geometry is a two-dimensional (2D) geometry that supports an altitude and a height. Sometimes these geometries are also referred to as "two-and-a-half-D" geometries. For example, here is a simple polygon and an extruded version of the same polygon (seen from an oblique view):

A LineString becomes a wall when extruded:

And a point becomes a post:

C.4. Boundary Cases

Geometry coordinates are interpreted strictly in 2-dimensional linear fashion. As such, geometries based on geodetic, or geographic angular, coordinates have special considerations when dealing with boundary cases along the edges of the coordinate space. The following sections cover how to represent datasets which need to correctly span the anti-meridian and/or the poles.

C.4.1. The Anti-Meridian

The anti-meridian, the boundary between the 180th and -180th meridians, is one area which special attention needs to be paid when using non-collection geometries, such as line strings, polygons, and envelopes. Non-collection geometries are not allowed to span the anti-meridian; they must be split on the anti-meridian and grouped into geometry collections. Each member geometry needs to include coordinates up to and including the anti-meridian boundary coordinates. Geometries that are not separated into regions which do not span the anti-meridian are interpreted strictly in 2-dimensional linear space and will be interpreted as if they span the opposite meridian (the prime meridian).

Take for instance a polygon defined by the following geometry OGC Well-Known Text (WKT):

POLYGON((150 -20,150 25,-150 25,-150 0))

Based solely on these coordinates it would be interpreted to span the area from -150 to 150 longitude. The figure below depicts how the above polygon would be interpreted. As you can see it crosses the prime meridian, which are the left and right edges of the figure below, and not the anti-meridian as we are intending.

Figure C.11. Polygon Trying to Span the Anti-meridian

Polygon Trying to Span the Anti-meridian

In order to span the anti-meridian, the polygon described above must be split into a multi-polygon representing the discrete areas between 150 and 180 longitude and between -180 and -150 longitude. To do this a segment running along the anti-meridian on both sides must be present in the coordinate values. This is shown in the following multi-polygon WKT:

MULTIPOLYGON(((150 -20,150 25,180 25,180 -20)),((-180 -20,-180 25,-150 25, -150 -20)))

The figure below depicts the above multi-polygon with boundary coordinates highlighted. As you can see it spans the area up to and including the anti-meridian on both sides, giving the correct spatial coverage.

Figure C.12. Polygon Separated into Multi-Polygon

Polygon Separated into Multi-Polygon


The same restriction applies also to line strings and envelopes, point geometries cannot cross the anti-meridian so they are exempt. Line strings must be split into multi-line strings; envelopes must be represented as a wrapped envelope, a two-part envelope, which is created using the Envelope.createEnvelope() method. Refer to the discussion on wrapped envelope geometries in Section C.1, “Geometry Object Model” for more details on creating them.

C.4.2. The Poles

Polygons or envelopes based on geodetic coordinates which need to span polar regions also have special considerations. Since geometries are 2-dimensional and interpreted linearly, these geometries must be created with coordinates representing the boundaries of the longitudinal and latitudinal axes of the coordinate system.

Consider the following figure which depicts a geodetic area encompassing the north pole, from about 70 degrees north latitude up to 90 degrees north latitude. This figure shows the earth as a sphere and how the area would appear as viewed from directly over the pole.

Figure C.13. Region Encompassing the North Pole

Region Encompassing the North Pole

To properly represent an area encompassing a pole like the one described in the above figure, the geometry's coordinate array must include coordinate pairs with the minimum and maximum longitudinal (X) axis values coupled with the maximum or minimum latitudinal (Y) axis values, depending on the pole being encompassed.

In the above figure, the north pole is a single point at 90 degrees which encompassing all longitudinal axis values. In order to accurately represent this area in a 2-dimensional geometry, that single point must be turned into a segment. This can be done by using the minimum and maximum longitude values coupled with the maximum latitude value (e.g. a segment with coordinates of -180,90 to 180,90). The other segments of the polygon run along both sides of the anti-meridian boundary down to the minimum latitude with a final segment spanning the longitudinal axis on the minimum latitude. This creates a band which spans the entire longitudinal axis and spans from 70 degrees north latitude up to 90 degrees north latitude. The coordinates needed to represent this polygon are shown in the following OGC Well-Known Text (WKT):

POLYGON((-180 80,-180 90,180 90,180 80))

The figure below depicts how the geometry defined above would look in the Plate Carrée projection for reference. As you can see in this projection, the single point of the pole is actually represented by a segment spanning the entire longitudinal axis. The boundary coordinates discussed above are highlighted.

Figure C.14. Polygon with Boundary Coordinates

Polygon with Boundary Coordinates


C.4.3. Other Edge Cases

The following additional examples in OGC Well-known text show special or unusual cases. These are included to illustrate how the coordinates of a polygon need to be constructed to be interpreted correctly with longitude/latitude data.

  • POLYGON((-180 -90,-180 90,180 90, 180 -90)) is the entire Earth.

  • POLYGON((-180 -90,-180 30,180 30,180 -90)) is the entire Earth below latitude 30 (inverse of example above).

  • POLYGON((25 -90,25 90,50 90,50 -90)) is a band from the South Pole to the North Pole between longitudes 25 and 50.

  • POLYGON((10 -90, 10 50, 40 50, 40 -90)) is a band from the South Pole to latitude 50 between longitudes 10 and 40.

  • POLYGON((-180 -10,-180 5,180 5,180 -10)) is a band that wraps the equator from 10 degrees south to 5 degrees north.

Glossary

The following is a glossary of terms used by SpatialRules. This glossary contains current as well as older and obsolete terms for historical reference.

Bounds

Version 2.0 only. Represented a spatial or temporal bound defining a specific region of space or time. This concept was replaced by "reference feature" for spatial bounds and "period" for temporal bounds

BoundsSet

Version 2.0 only. Represented a collection of bounds that can be referenced from a rule to apply logic over a set of spatial or temporal bounds. This term has been replaced with FeatureSet.

Comparator

Part of an expression used to compare values.

ConditionBounds

Version 2.0 only. The Java class used to represent a named spatial or temporal bound. This has been replaced with Feature.

Data Type

Different data types are supported for attribute values. The types must be explicitly indicated when performing operations on different data types. Supported data types include (char, number, date)

DynamicFeature

As of version 3.0. Objects that are submitted to SpatialRules for evaluation. In previous versions this was named Locatable or LocatableObject.

Expression

The logic used to encode a rule. The terms rule and expression are interchangeable. An expression can be encoded using Java or RulesScript.

InputClient

Class used by applications to communicate with the SpatialRules server. The input client provides mechanisms for converting data formats and handling errors.

Locatable

Version 2.0 only. Refers to a location report submitted to the rule engine. This term is synonymous with "object of interest" or "entity". This term has been replaced with "Dynamic Feature."

Location

The position (lon, lat) and capture time referenced in a location report. For versions 3.0 and above the location may contain any supported geometry.

Location Report

Refers to a single piece of data about a Dynamic Feature that can be submitted to the rule engine for evaluation. The data contains an ID, type, location/geometry, timestamp, and an optional set of business attributes.

OGC

Open Geospatial Consortium (www.opengeospatial.org).

RecurringTime

The Java class used to represent a recurring time frame.

Result

The object containing evaluation results including the subject, a set of targets, and the name of the rule that evaluated to True.

Rules Server

Service that resides within the SpatialRules server that accepts incoming data. The Rules Server communicates with the InputClient.

Server

SpatialRules server that is run from the command line.

Subject

The subject object of interest (i.e., DynamicFeature) that is evaluated by a set of rules. When a rule evaluates to True, the result will contain the subject feature that was involved in making the expression True.

Target

The target is either a bounds or locatable involved in a rule expression. When a rule evaluates to True, the result will contain a list of zero or more targets that were involved in making the expression True.

TemporalBounds

Version 2.0 only. The Java class used to represent a temporal bounds, either fixed or recurring. This has been replaced with Period.

Bibliography

[crs] Geographic information — Spatial referencing by coordinates. 2004-08-02. International Organization for Standardization (ISO). ISO/DIS 19111.

[filter-encoding-spec] OpenGIS® Filter Encoding Implementation Specification. 1.1.0. 3 May 2005. Open Geospatial Consortium Inc.. Panagiotis A. Vretanos. OGC 04-095.

[simple-feature-spec] OpenGIS® Implementation Specification for Geographic information — Simple feature access — Part 1: Common architecture. 1.2.0. 2006-10-05. Open Geospatial Consortium Inc.. John R. Herring. OGC 06-103r3.

[spatial-schema] Geographic information — Spatial schema. 2003-05-01. International Organization for Standardization (ISO). ISO 19107:2003(E).

[wms-spec] OpenGIS® Web Map Server Implementation Specification. 1.3.0. 2006-03-15. Open Geospatial Consortium Inc.. Jeff de la Beaujardiere. OGC 06-042.