docs: static boolean relate(Geometry geometry_a, Geometry geometry_b,
  			SpatialReference sr, String scl, ProgressTracker progress_tracker) {
  
          if (scl.length() != 9)
              throw new GeometryException("relation string length has to be 9 characters");
  
          for (int i = 0; i < 9; i++)
          {
              char c = scl.charAt(i);
  
              if (c != '*' && c != 'T' && c != 'F' && c != '0' && c != '1' && c != '2')
                  throw new GeometryException("relation string");
          }
  
          int relation = getPredefinedRelation_(scl, geometry_a.getDimension(),
  				geometry_b.getDimension());
  
  		if (relation != RelationalOperations.Relation.unknown)
  			return RelationalOperations.relate(geometry_a, geometry_b, sr,
  					relation, progress_tracker);
  
  		Envelope2D env1 = new Envelope2D();
  		geometry_a.queryEnvelope2D(env1);
  		Envelope2D env2 = new Envelope2D();
  		geometry_b.queryEnvelope2D(env2);
  
  		Envelope2D envMerged = new Envelope2D();
  		envMerged.setCoords(env1);
  		envMerged.merge(env2);
  		double tolerance = InternalUtils.calculateToleranceFromGeometry(sr,
  				envMerged, false);
  
  		Geometry _geometryA = convertGeometry_(geometry_a, tolerance);
  		Geometry _geometryB = convertGeometry_(geometry_b, tolerance);
  
          if (_geometryA.isEmpty() || _geometryB.isEmpty())
              return relateEmptyGeometries_(_geometryA, _geometryB, scl);
  
  		int typeA = _geometryA.getType().value();
  		int typeB = _geometryB.getType().value();
  
  		boolean bRelation = false;
  
  		switch (typeA) {
  		case Geometry.GeometryType.Polygon:
  			switch (typeB) {
  			case Geometry.GeometryType.Polygon:
  				bRelation = polygonRelatePolygon_((Polygon) (_geometryA),
  						(Polygon) (_geometryB), tolerance, scl,
  						progress_tracker);
  				break;
  
  			case Geometry.GeometryType.Polyline:
  				bRelation = polygonRelatePolyline_((Polygon) (_geometryA),
  						(Polyline) (_geometryB), tolerance, scl,
  						progress_tracker);
  				break;
  
  			case Geometry.GeometryType.Point:
  				bRelation = polygonRelatePoint_((Polygon) (_geometryA),
  						(Point) (_geometryB), tolerance, scl, progress_tracker);
  				break;
  
  			case Geometry.GeometryType.MultiPoint:
  				bRelation = polygonRelateMultiPoint_((Polygon) (_geometryA),
  						(MultiPoint) (_geometryB), tolerance, scl,
  						progress_tracker);
  				break;
  
  			default:
  				break; // warning fix
  			}
  			break;
  
  		case Geometry.GeometryType.Polyline:
  			switch (typeB) {
  			case Geometry.GeometryType.Polygon:
  				bRelation = polygonRelatePolyline_((Polygon) (_geometryB),
  						(Polyline) (_geometryA), tolerance,
  						getTransposeMatrix_(scl), progress_tracker);
  				break;
  
  			case Geometry.GeometryType.Polyline:
  				bRelation = polylineRelatePolyline_((Polyline) (_geometryA),
  						(Polyline) (_geometryB), tolerance, scl,
  						progress_tracker);
  				break;
  
  			case Geometry.GeometryType.Point:
  				bRelation = polylineRelatePoint_((Polyline) (_geometryA),
  						(Point) (_geometryB), tolerance, scl, progress_tracker);
  				break;
  
  			case Geometry.GeometryType.MultiPoint:
  				bRelation = polylineRelateMultiPoint_((Polyline) (_geometryA),
  						(MultiPoint) (_geometryB), tolerance, scl,
  						progress_tracker);
  				break;
  
  			default:
  				break; // warning fix
  			}
  			break;
  
  		case Geometry.GeometryType.Point:
  			switch (typeB) {
  			case Geometry.GeometryType.Polygon:
  				bRelation = polygonRelatePoint_((Polygon) (_geometryB),
  						(Point) (_geometryA), tolerance,
  						getTransposeMatrix_(scl), progress_tracker);
  				break;
  
  			case Geometry.GeometryType.Polyline:
  				bRelation = polylineRelatePoint_((Polyline) (_geometryB),
  						(Point) (_geometryA), tolerance,
  						getTransposeMatrix_(scl), progress_tracker);
  				break;
  
  			case Geometry.GeometryType.Point:
  				bRelation = pointRelatePoint_((Point) (_geometryA),
  						(Point) (_geometryB), tolerance, scl, progress_tracker);
  				break;
  
  			case Geometry.GeometryType.MultiPoint:
  				bRelation = multiPointRelatePoint_((MultiPoint) (_geometryB),
  						(Point) (_geometryA), tolerance,
  						getTransposeMatrix_(scl), progress_tracker);
  				break;
  
  			default:
  				break; // warning fix
  			}
  			break;
  
  		case Geometry.GeometryType.MultiPoint:
  			switch (typeB) {
  			case Geometry.GeometryType.Polygon:
  				bRelation = polygonRelateMultiPoint_((Polygon) (_geometryB),
  						(MultiPoint) (_geometryA), tolerance,
  						getTransposeMatrix_(scl), progress_tracker);
  				break;
  
  			case Geometry.GeometryType.Polyline:
  				bRelation = polylineRelateMultiPoint_((Polyline) (_geometryB),
  						(MultiPoint) (_geometryA), tolerance,
  						getTransposeMatrix_(scl), progress_tracker);
  				break;
  
  			case Geometry.GeometryType.MultiPoint:
  				bRelation = multiPointRelateMultiPoint_(
  						(MultiPoint) (_geometryA), (MultiPoint) (_geometryB),
  						tolerance, scl, progress_tracker);
  				break;
  
  			case Geometry.GeometryType.Point:
  				bRelation = multiPointRelatePoint_((MultiPoint) (_geometryA),
  						(Point) (_geometryB), tolerance, scl, progress_tracker);
  				break;
  
  			default:
  				break; // warning fix
  			}
  			break;
  		default:
  			bRelation = false;
  			break;
  		}
  
  		return bRelation;
  	}