This article describes how to create custom topological relations for the ILcd2DAdvancedBinaryTopology interface. Make sure you are familiar with the key concepts of the DE-9IM model before reading this article.

The method checkTopology of an ILcd2DAdvancedBinaryTopology instance has three parameters: two shapes and the topological relation that you want to compute for these two shapes. Instead of using a predefined topological relation , you can also define a custom relation.

Creating a custom topological relation requires a new implementation of the interface ILcdIntersectionMatrixPattern which can be passed on as third argument to the method checkTopology.

This comes down to implementing the method matches of the interface ILcdIntersectionMatrixPattern. This method takes an ILcdIntersectionMatrix instance as argument and returns a boolean value indicating whether this intersection matrix passes the set of conditions imposed by the custom topological relation. This set of conditions could depend on the nine elements of the intersection matrix and the dimensions of the two involved shapes.

Program: Example of creating a custom topological relation
/**
 * Custom defined topological relation which can be used with the {@link ILcd2DAdvancedBinaryTopology} interface.
 * This example emulates the line-intersect relation which exists in
 * {@linkplain com.luciad.geometry.ILcd2DBinaryTopology#LINE_INTERSECT the binary topology interface}.
 */
public static class LineIntersect implements ILcdIntersectionMatrixPattern {

  @Override
  public boolean matches(ILcdIntersectionMatrix aMatrix) {

    // Get shape dimensions.
    ELcdGeometryDimension dim1 = aMatrix.getShapeDimension(0);
    ELcdGeometryDimension dim2 = aMatrix.getShapeDimension(1);

    // Get required element dimensions.
    ELcdGeometryDimension dimII = aMatrix.getDimension(ELcdGeometryRegion.INTERIOR, ELcdGeometryRegion.INTERIOR);
    ELcdGeometryDimension dimIB = aMatrix.getDimension(ELcdGeometryRegion.INTERIOR, ELcdGeometryRegion.BOUNDARY);
    ELcdGeometryDimension dimBI = aMatrix.getDimension(ELcdGeometryRegion.BOUNDARY, ELcdGeometryRegion.INTERIOR);
    ELcdGeometryDimension dimBB = aMatrix.getDimension(ELcdGeometryRegion.BOUNDARY, ELcdGeometryRegion.BOUNDARY);

    if (dim1 == ELcdGeometryDimension.POINT || dim2 == ELcdGeometryDimension.POINT) {
      // Points do not line intersect
      return false;
    } else if (dim1 == ELcdGeometryDimension.LINE && dim2 == ELcdGeometryDimension.LINE) {
      // Two lines intersect if their interiors and/or boundaries intersect.
      return dimII != ELcdGeometryDimension.FALSE || dimIB != ELcdGeometryDimension.FALSE ||
             dimBI != ELcdGeometryDimension.FALSE || dimBB != ELcdGeometryDimension.FALSE;
    } else if (dim1 == ELcdGeometryDimension.LINE && dim2 == ELcdGeometryDimension.AREA) {
      // A line and an area line intersect if the interior or the boundary
      // of the line intersects the boundary of the area.
      return dimIB != ELcdGeometryDimension.FALSE || dimBB != ELcdGeometryDimension.FALSE;
    } else if (dim1 == ELcdGeometryDimension.AREA && dim2 == ELcdGeometryDimension.LINE) {
      // A line and an area line intersect if the interior or the boundary
      // of the line intersects the boundary of the area.
      return dimBI != ELcdGeometryDimension.FALSE || dimBB != ELcdGeometryDimension.FALSE;
    } else if (dim1 == ELcdGeometryDimension.AREA && dim2 == ELcdGeometryDimension.AREA) {
      // Two areas line intersect if their boundaries intersect.
      return dimBB != ELcdGeometryDimension.FALSE;
    }

    return false;
  }
}

Once the relationship is created, you can use it like you use the predefined relationships:

public static void main(String[] args) {
  // Test two shapes with the new LineIntersect relation.
  TLcdXYPolyline shape1 = new TLcdXYPolyline(new TLcd2DEditablePointList(new ILcd2DEditablePoint[]{
      new TLcdXYPoint(0.0, 0.0),
      new TLcdXYPoint(10.0, 10.0)}, false));
  TLcdXYPolyline shape2 = new TLcdXYPolyline(new TLcd2DEditablePointList(new ILcd2DEditablePoint[]{
      new TLcdXYPoint(0.0, 10.0),
      new TLcdXYPoint(10.0, 0.0)}, false));

  // Create the advanced binary topology.
  ILcd2DAdvancedBinaryTopology topology = new TLcdCartesianAdvancedBinaryTopology();

  ILcdIntersectionMatrixPattern LINE_INTERSECT = new LineIntersect();

  // Test if the shapes line intersect.
  boolean line_intersects = topology.checkTopology(shape1, shape2, LINE_INTERSECT);
  System.out.println("The lines intersect: " + line_intersects);
}

Full code

import com.luciad.geometry.ELcdGeometryDimension;
import com.luciad.geometry.ELcdGeometryRegion;
import com.luciad.geometry.ILcd2DAdvancedBinaryTopology;
import com.luciad.geometry.ILcdIntersectionMatrix;
import com.luciad.geometry.ILcdIntersectionMatrixPattern;
import com.luciad.geometry.cartesian.TLcdCartesianAdvancedBinaryTopology;
import com.luciad.shape.shape2D.ILcd2DEditablePoint;
import com.luciad.shape.shape2D.TLcd2DEditablePointList;
import com.luciad.shape.shape2D.TLcdXYPoint;
import com.luciad.shape.shape2D.TLcdXYPolyline;

public class CreateCustomRelationSnippets {

  /**
   * Custom defined topological relation which can be used with the {@link ILcd2DAdvancedBinaryTopology} interface.
   * This example emulates the line-intersect relation which exists in
   * {@linkplain com.luciad.geometry.ILcd2DBinaryTopology#LINE_INTERSECT the binary topology interface}.
   */
  public static class LineIntersect implements ILcdIntersectionMatrixPattern {

    @Override
    public boolean matches(ILcdIntersectionMatrix aMatrix) {

      // Get shape dimensions.
      ELcdGeometryDimension dim1 = aMatrix.getShapeDimension(0);
      ELcdGeometryDimension dim2 = aMatrix.getShapeDimension(1);

      // Get required element dimensions.
      ELcdGeometryDimension dimII = aMatrix.getDimension(ELcdGeometryRegion.INTERIOR, ELcdGeometryRegion.INTERIOR);
      ELcdGeometryDimension dimIB = aMatrix.getDimension(ELcdGeometryRegion.INTERIOR, ELcdGeometryRegion.BOUNDARY);
      ELcdGeometryDimension dimBI = aMatrix.getDimension(ELcdGeometryRegion.BOUNDARY, ELcdGeometryRegion.INTERIOR);
      ELcdGeometryDimension dimBB = aMatrix.getDimension(ELcdGeometryRegion.BOUNDARY, ELcdGeometryRegion.BOUNDARY);

      if (dim1 == ELcdGeometryDimension.POINT || dim2 == ELcdGeometryDimension.POINT) {
        // Points do not line intersect
        return false;
      } else if (dim1 == ELcdGeometryDimension.LINE && dim2 == ELcdGeometryDimension.LINE) {
        // Two lines intersect if their interiors and/or boundaries intersect.
        return dimII != ELcdGeometryDimension.FALSE || dimIB != ELcdGeometryDimension.FALSE ||
               dimBI != ELcdGeometryDimension.FALSE || dimBB != ELcdGeometryDimension.FALSE;
      } else if (dim1 == ELcdGeometryDimension.LINE && dim2 == ELcdGeometryDimension.AREA) {
        // A line and an area line intersect if the interior or the boundary
        // of the line intersects the boundary of the area.
        return dimIB != ELcdGeometryDimension.FALSE || dimBB != ELcdGeometryDimension.FALSE;
      } else if (dim1 == ELcdGeometryDimension.AREA && dim2 == ELcdGeometryDimension.LINE) {
        // A line and an area line intersect if the interior or the boundary
        // of the line intersects the boundary of the area.
        return dimBI != ELcdGeometryDimension.FALSE || dimBB != ELcdGeometryDimension.FALSE;
      } else if (dim1 == ELcdGeometryDimension.AREA && dim2 == ELcdGeometryDimension.AREA) {
        // Two areas line intersect if their boundaries intersect.
        return dimBB != ELcdGeometryDimension.FALSE;
      }

      return false;
    }
  }

  public static void main(String[] args) {
    // Test two shapes with the new LineIntersect relation.
    TLcdXYPolyline shape1 = new TLcdXYPolyline(new TLcd2DEditablePointList(new ILcd2DEditablePoint[]{
        new TLcdXYPoint(0.0, 0.0),
        new TLcdXYPoint(10.0, 10.0)}, false));
    TLcdXYPolyline shape2 = new TLcdXYPolyline(new TLcd2DEditablePointList(new ILcd2DEditablePoint[]{
        new TLcdXYPoint(0.0, 10.0),
        new TLcdXYPoint(10.0, 0.0)}, false));

    // Create the advanced binary topology.
    ILcd2DAdvancedBinaryTopology topology = new TLcdCartesianAdvancedBinaryTopology();

    ILcdIntersectionMatrixPattern LINE_INTERSECT = new LineIntersect();

    // Test if the shapes line intersect.
    boolean line_intersects = topology.checkTopology(shape1, shape2, LINE_INTERSECT);
    System.out.println("The lines intersect: " + line_intersects);
  }
}