Skip to content

Commit

Permalink
Add IsInsideExternalDatasetResource function
Browse files Browse the repository at this point in the history
  • Loading branch information
domi-b committed Dec 21, 2023
1 parent df6c266 commit 71c1693
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -150,17 +150,23 @@ private Collection<IomObject> extractChBaseSurfaceGeometryFromAttribute(IomObjec
}

protected static final class ValidAreaKey {
private final String dataSource;
private final String datasetName;
private final String[] transferIds;

ValidAreaKey(String datasetName, String transferIds) {
ValidAreaKey(String dataSource, String datasetName, String transferIds) {
this.dataSource = dataSource;
this.datasetName = datasetName;

String[] splitTransferIds = transferIds.split("\\s*,\\s*");
Arrays.sort(splitTransferIds);
this.transferIds = splitTransferIds;
}

public String getDataSource() {
return dataSource;
}

public String getDatasetName() {
return datasetName;
}
Expand All @@ -178,12 +184,12 @@ public boolean equals(Object o) {
return false;
}
ValidAreaKey that = (ValidAreaKey) o;
return Objects.equals(datasetName, that.datasetName) && Arrays.equals(transferIds, that.transferIds);
return Objects.equals(dataSource, that.dataSource) && Objects.equals(datasetName, that.datasetName) && Arrays.equals(transferIds, that.transferIds);
}

@Override
public int hashCode() {
int result = Objects.hash(datasetName);
int result = Objects.hash(dataSource, datasetName);
result = 31 * result + Arrays.hashCode(transferIds);
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected Value evaluateInternal(String validationKind, String usageScope, IomOb

String transferIds = argObjects.getValue();
String datasetName = argDatasetName.getValue();
ValidAreaKey key = new ValidAreaKey(datasetName, transferIds);
ValidAreaKey key = new ValidAreaKey(null, datasetName, transferIds);
String testObjectGeometryAttribute = argTestObjectgeometry.getValue();

return isInsideValidArea(usageScope, key, argTestObject.getComplexObjects(), testObjectGeometryAttribute);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package ch.geowerkstatt.ilivalidator.extensions.functions;

import ch.interlis.iom.IomObject;
import ch.interlis.iox_j.validator.Value;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Polygon;

import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.List;

public final class IsInsideExternalDatasetResourceIoxPlugin extends BaseIsInsideFunction {
private static final String QUALIFIED_ILI_NAME = "GeoW_FunctionsExt.IsInsideExternalDatasetResource";

@Override
public String getQualifiedIliName() {
return QUALIFIED_ILI_NAME;
}

@Override
protected Value evaluateInternal(String validationKind, String usageScope, IomObject mainObj, Value[] arguments) {
Value argTransferFile = arguments[0]; // TEXT
Value argDatasetName = arguments[1]; // TEXT
Value argObjects = arguments[2]; // TEXT
Value argTestObject = arguments[3]; // OBJECT OF ANYCLASS
Value argTestObjectgeometry = arguments[4]; // TEXT

if (argTransferFile.isUndefined() || argDatasetName.isUndefined() || argObjects.isUndefined() || argTestObject.isUndefined() || argTestObjectgeometry.isUndefined()) {
return Value.createSkipEvaluation();
}

String transferFile = argTransferFile.getValue();
String transferIds = argObjects.getValue();
String datasetName = argDatasetName.getValue();
ValidAreaKey key = new ValidAreaKey(transferFile, datasetName, transferIds);
String testObjectGeometryAttribute = argTestObjectgeometry.getValue();

return isInsideValidArea(usageScope, key, argTestObject.getComplexObjects(), testObjectGeometryAttribute);
}

@Override
protected Geometry getValidArea(ValidAreaKey key) {
String transferFile = key.getDataSource();
String datasetName = key.getDatasetName();
int lastPoint = datasetName.lastIndexOf('.');
if (lastPoint == -1) {
throw new IllegalStateException(MessageFormat.format("Expected qualified attribute name but got <{0}>.", datasetName));
}

String attribute = datasetName.substring(lastPoint + 1);
String qualifiedClass = datasetName.substring(0, lastPoint);

Polygon[] polygons = readPolygonsFromTransferFile(transferFile, key.getTransferIds(), qualifiedClass, attribute);

Geometry geometryCollection = new GeometryFactory().createGeometryCollection(polygons);
return geometryCollection.buffer(0);
}

private Polygon[] readPolygonsFromTransferFile(String transferFile, String[] transferIds, String qualifiedClass, String attribute) {
ClassLoader loader = getClass().getClassLoader();
try (InputStream stream = loader.getResourceAsStream(transferFile)) {
if (stream == null) {
throw new IllegalStateException(MessageFormat.format("Could not find Transferfile <{0}> in resources.", transferFile));
}

List<IomObject> objects = XtfHelper.getObjectsFromXTF(stream, qualifiedClass, transferIds);
return getPolygonsFromObjects(objects.stream(), attribute);
} catch (IOException e) {
throw new IllegalStateException(MessageFormat.format("Unable to read Transferfile <{0}>.", transferFile), e);
}
}
}
6 changes: 6 additions & 0 deletions src/model/GeoW_FunctionsExt.ili
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ MODEL GeoW_FunctionsExt
!!@ fn.since = "2022-12-05";
FUNCTION IsInsideExternalDataset (DatasetName: TEXT; Objects: TEXT; TestObject: OBJECT OF ANYCLASS; TestObjectgeometry: TEXT): BOOLEAN;

!!@ fn.description = "Prüft, ob ein Objekt innerhalb einer gegebenen Testgeometrie liegt, welche aus einem externen Datensatz innerhalb der Ressourcen stammt. Der externe Datensatz muss sich in einer INTERLIS 2.3 Transferdatei befinden, die über den angegebenen Pfad als Ressource erreichbar ist.";
!!@ fn.param = "TransferFile: Qualifizierter Name der Transferdatei-Ressource. DatasetName: Qualifizierter Name des Attributes aus dem Transfermodells, in welchem die Objekte zur Prüfung bereitliegen. Objects: Objekt(e), über die TID identifiziert, welche zur Prüfung beigezogen werden. TestObject: Objekt, welches zu prüfen ist. TestObjectgeometry: Geometriefeld, bezogen auf das unter Testobject übergebene Objekt";
!!@ fn.return = "Boolean";
!!@ fn.since = "2023-12-20";
FUNCTION IsInsideExternalDatasetResource (TransferFile: TEXT; DatasetName: TEXT; Objects: TEXT; TestObject: OBJECT OF ANYCLASS; TestObjectgeometry: TEXT): BOOLEAN;

!!@ fn.description = "Fasst die Flächen-Geometrien aus der Eingabemenge zu einer Flächen-Geometrie zusammen. Für 'Geometries' können nur Geometrien angegeben werden.";
!!@ fn.param = "Geometries: Geometrien, die zusammengefasst werden sollen";
!!@ fn.return = "Zusammengefasste Flächen-Geometrie";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
INTERLIS 2.4;

MODEL TestSuite
AT "mailto:[email protected]" VERSION "2023-12-20" =
IMPORTS GeoW_FunctionsExt;

DOMAIN
!!@CRS=EPSG:2056
CHKoord = COORD 2460000.000 .. 2870000.000 [INTERLIS.m],
1045000.000 .. 1310000.000 [INTERLIS.m],
ROTATION 2 -> 1;

TOPIC FunctionTestTopic =
CLASS ConstraintTestClass (ABSTRACT) =
expected : MANDATORY BOOLEAN;
END ConstraintTestClass;

CLASS IsInsideSOKantonsgrenze EXTENDS ConstraintTestClass =
testAttributeIsInsideSOKantonsgrenze : CHKoord;
MANDATORY CONSTRAINT IsInsideSOKantonsgrenze: GeoW_FunctionsExt.IsInsideExternalDatasetResource("IsInsideExternalDatasetResource/ch.so.agi.av.hoheitsgrenzen_excerpt.xtf", "SO_Hoheitsgrenzen_Publikation_20170626.Hoheitsgrenzen.Kantonsgrenze.Geometrie", "fubar", THIS, "testAttributeIsInsideCHBaseGeometrie") == expected;
END IsInsideSOKantonsgrenze;

CLASS InvalidConstraints =
geometryAttribute : CHKoord;
MANDATORY CONSTRAINT MalformedDatasetName: GeoW_FunctionsExt.IsInsideExternalDatasetResource("IsInsideExternalDatasetResource/ch.so.agi.av.hoheitsgrenzen_excerpt.xtf", "DatasetNameWithoutQualifiedAttribute", "fubar", THIS, "geometryAttribute");
MANDATORY CONSTRAINT NonExistentTransferFile: GeoW_FunctionsExt.IsInsideExternalDatasetResource("NotExistingFile.xtf", "SO_Hoheitsgrenzen_Publikation_20170626.Hoheitsgrenzen.Kantonsgrenze.Geometrie", "fubar", THIS, "geometryAttribute");
MANDATORY CONSTRAINT NonExistentTransferIds: GeoW_FunctionsExt.IsInsideExternalDatasetResource("IsInsideExternalDatasetResource/ch.so.agi.av.hoheitsgrenzen_excerpt.xtf", "SO_Hoheitsgrenzen_Publikation_20170626.Hoheitsgrenzen.Kantonsgrenze.Geometrie", "9999,100000000", THIS, "geometryAttribute");
END InvalidConstraints;

END FunctionTestTopic;

END TestSuite.
32 changes: 32 additions & 0 deletions src/test/data/IsInsideExternalDatasetResource/TestData.xtf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ili:transfer xmlns:ili="http://www.interlis.ch/xtf/2.4/INTERLIS" xmlns:geom="http://www.interlis.ch/geometry/1.0"
xmlns:TestSuite="http://www.interlis.ch/xtf/2.4/TestSuite">
<ili:headersection>
<ili:models>
<ili:model>GeoW_FunctionsExt</ili:model>
<ili:model>TestSuite</ili:model>
</ili:models>
<ili:sender>ili2gpkg-4.6.1-63db90def1260a503f0f2d4cb846686cd4851184</ili:sender>
</ili:headersection>
<ili:datasection>
<TestSuite:FunctionTestTopic ili:bid="TestSuite.FunctionTestTopic">
<TestSuite:InvalidConstraints ili:tid="1">
<TestSuite:geometryAttribute>
<geom:coord>
<geom:c1>2533306.953</geom:c1>
<geom:c2>1184710.792</geom:c2>
</geom:coord>
</TestSuite:geometryAttribute>
</TestSuite:InvalidConstraints>
<TestSuite:IsInsideSOKantonsgrenze ili:tid="2"> <!-- Erwartet: 2D-Punkt: liegt im Kt. SO -->
<TestSuite:expected>true</TestSuite:expected>
<TestSuite:testAttributeIsInsideSOKantonsgrenze>
<geom:coord>
<geom:c1>2620570.500</geom:c1>
<geom:c2>1237151.400</geom:c2>
</geom:coord>
</TestSuite:testAttributeIsInsideSOKantonsgrenze>
</TestSuite:IsInsideSOKantonsgrenze>
</TestSuite:FunctionTestTopic>
</ili:datasection>
</ili:transfer>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ch.geowerkstatt.ilivalidator.extensions.functions;

import ch.interlis.ili2c.Ili2cFailure;
import ch.interlis.iox.IoxException;
import com.vividsolutions.jts.util.Assert;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public final class IsInsideExternalDatasetResourceIoxPluginTest {
private static final String TEST_DATA = "IsInsideExternalDatasetResource/TestData.xtf";
private ValidationTestHelper vh;

@BeforeEach
void setUp() {
vh = new ValidationTestHelper();
vh.addFunction(new IsInsideExternalDatasetResourceIoxPlugin());
}

@Test
void isInsideResourceDataset() throws Ili2cFailure, IoxException {
vh.runValidation(new String[]{TEST_DATA}, new String[]{"IsInsideExternalDatasetResource/MandatoryConstraintThis.ili"});

Assert.equals(6, vh.getErrs().size());
AssertionHelper.assertLogEventsContainMessage(vh.getErrs(), "TestSuite.FunctionTestTopic.InvalidConstraints.MalformedDatasetName: Unable to evaluate GeoW_FunctionsExt.IsInsideExternalDatasetResource. Expected qualified attribute name but got <DatasetNameWithoutQualifiedAttribute>.");
AssertionHelper.assertLogEventsContainMessage(vh.getErrs(), "TestSuite.FunctionTestTopic.InvalidConstraints.NonExistentTransferFile: Unable to evaluate GeoW_FunctionsExt.IsInsideExternalDatasetResource. Could not find Transferfile <NotExistingFile.xtf> in resources.");
AssertionHelper.assertLogEventsContainMessage(vh.getErrs(), "TestSuite.FunctionTestTopic.InvalidConstraints.NonExistentTransferIds: Unable to evaluate GeoW_FunctionsExt.IsInsideExternalDatasetResource. Could not find objects with TID <100000000, 9999> in transfer file");
AssertionHelper.assertLogEventsContainMessage(vh.getErrs(), "Mandatory Constraint TestSuite.FunctionTestTopic.InvalidConstraints.MalformedDatasetName is not true.");
AssertionHelper.assertLogEventsContainMessage(vh.getErrs(), "Mandatory Constraint TestSuite.FunctionTestTopic.InvalidConstraints.NonExistentTransferFile is not true.");
AssertionHelper.assertLogEventsContainMessage(vh.getErrs(), "Mandatory Constraint TestSuite.FunctionTestTopic.InvalidConstraints.NonExistentTransferIds is not true.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?><TRANSFER xmlns="http://www.interlis.ch/INTERLIS2.3">
<HEADERSECTION SENDER="ili2pg-4.9.0-eb3a0d51869bd2adeeb51fe7aba4b526fe002c1a" VERSION="2.3"><MODELS><MODEL NAME="SO_Hoheitsgrenzen_Publikation_20170626" VERSION="2017-06-26" URI="http://www.geo.so.ch/models/AGI"></MODEL></MODELS></HEADERSECTION>
<DATASECTION>
<SO_Hoheitsgrenzen_Publikation_20170626.Hoheitsgrenzen BID="SO_Hoheitsgrenzen_Publikation_20170626.Hoheitsgrenzen">
<SO_Hoheitsgrenzen_Publikation_20170626.Hoheitsgrenzen.Kantonsgrenze TID="fubar"><Kantonsname>Solothurn</Kantonsname><Geometrie><GeometryCHLV95_V1.MultiSurface><Surfaces><GeometryCHLV95_V1.SurfaceStructure><Surface><SURFACE><BOUNDARY><POLYLINE><COORD><C1>2591994.000</C1><C2>1262353.000</C2></COORD><COORD><C1>2645900.000</C1><C2>1262353.000</C2></COORD><COORD><C1>2645900.000</C1><C2>1211927.000</C2></COORD><COORD><C1>2591994.000</C1><C2>1211927.000</C2></COORD><COORD><C1>2591994.000</C1><C2>1262353.000</C2></COORD></POLYLINE></BOUNDARY></SURFACE></Surface></GeometryCHLV95_V1.SurfaceStructure></Surfaces></GeometryCHLV95_V1.MultiSurface></Geometrie><Kantonskuerzel>SO</Kantonskuerzel><Kantonsnummer>11</Kantonsnummer></SO_Hoheitsgrenzen_Publikation_20170626.Hoheitsgrenzen.Kantonsgrenze>
</SO_Hoheitsgrenzen_Publikation_20170626.Hoheitsgrenzen>
</DATASECTION>
</TRANSFER>

0 comments on commit 71c1693

Please sign in to comment.