The ShapeLogic logic system is not quite a language, but it has become more organized with v. 0.8, 0.9 and 1.0.
For a broader introduction to the logic system see Declarative logic.
This was fine for handling simple rules applied to one polygon.
IoC hold potential but has not been used yet.
One possible problem with moving rules to Java 6 Scripting, is that this requires that the user downloads engine interface files from Sun. This would make the installation of ShapeLogic more complicated now it is just unpacking a zip and moving it into ImageJ's plugin dir.
The only scripting language that works out of the box is JavaScript. While that is a reasonable language the integration with Java is not so great especially not Java 5.
It is also possible to connect Groovy and Java outside Java 6 Scripting, but then it would not be uniform.
DigitStreamVectorizer is an example showing what is needed to define a match of the numbers working as a plugin from ImageJ.
rule("A", POINT_COUNT, "==", 5.); rule("A", HOLE_COUNT, "==", 1.); rule("A", T_JUNCTION_LEFT_POINT_COUNT,"==", 1.); rule("A", T_JUNCTION_RIGHT_POINT_COUNT,"==", 1.); rule("A", END_POINT_BOTTOM_POINT_COUNT, "==", 2.); rule("A", HORIZONTAL_LINE_COUNT, "==", 1.); rule("A", VERTICAL_LINE_COUNT, "==", 0.); rule("A", END_POINT_COUNT, "==", 2.); rule("A", SOFT_POINT_COUNT, "==", 0.);
The "A" is saying apply this rule to the OH, object hypothesis, the letter A.
The next is just names of streams that generate the point count and hole count for the polygons. Then there is the predicate and the comparison value.
Lazy streams have the following features
There are currently 3 main places where logic expressions can be placed:
Found named values are set in a JEXL context and expressions can be evaluated here too.
They are sub class of the Parametric Rule Tasks. They come in 2 flavors now:
You can also do logical combinations of the filter tasks:
So if you have one class with a filter criteria that is filtering:
You can combine them with and and to get a filter that filters, T junctions in the upper half.
The rules for all the capital letters can be found in the class: LetterTaskFactory.java
So each line will be translated into one task / goal.
new NumericRule("A", POINT_COUNT, polygon, VAR_SIZE_START + POINT_COUNT_EX + VAR_SIZE_END,"==", 5.), new NumericRule("A", HOLE_COUNT, polygon, VAR + HOLE_COUNT_EX, "==", 1.), new NumericRule("A", T_JUNCTION_LEFT_POINT_COUNT, polygon, FILTER_START + T_JUNCTION_LEFT_POINT_COUNT_EX + FILTER_END,"==", 1.), new NumericRule("A", T_JUNCTION_RIGHT_POINT_COUNT, polygon, filter(T_JUNCTION_RIGHT_POINT_COUNT_EX),"==", 1.), new NumericRule("A", END_POINT_BOTTOM_POINT_COUNT, polygon, filter(END_POINT_BOTTOM_POINT_COUNT_EX), "==", 2.), new NumericRule("A", HORIZONTAL_LINE_COUNT, polygon, size(HORIZONTAL_LINE_COUNT_EX), "==", 1.), new NumericRule("A", VERTICAL_LINE_COUNT, polygon, size(VERTICAL_LINE_COUNT_EX), "==", 0.), new NumericRule("A", END_POINT_COUNT, polygon, VAR + END_POINT_COUNT_EX, "==", 2.), new NumericRule("A", SOFT_POINT_COUNT, polygon, size(SOFT_POINT_COUNT_ANN_EX), "==", 0.),
All rules work in a JEXL context.
Steps when running letter match:
new NumericRule("A", HOLE_COUNT, polygon, VAR + HOLE_COUNT_EX, "==", 1.),
This will be transformed into a task that:
It is using # as a place holder for the name of the variable from last field.
E.g. "ploygon.holeCount"
Takes the variable coming in from the third field and add that to the expression in HOLE_COUNT_EX.
Evaluate the expression that the string constant VERTICAL_LINE_COUNT_EX.
This will return a collection of lines.
Then does a size() call on that to see how many element there are in it.
When you need filter a collection with the criteria expression inside the filter.
And then see how many elements the filter returns.
So in this case you start with all the points in the polygon.
The string: END_POINT_BOTTOM_POINT_COUNT_EX has the value:
"PointOfTypeFilter(PointType.END_POINT) && PointBelowFilter(0.5)"
This is a composite criteria that checks that the point is an end point and that it is in the lower half of the bounding box for the polygon.
You can use the normal boolean operators in the filter expression: and, or, not.