Skip to content

Commit

Permalink
Merge pull request #45 Add geometry attribute parameter to IsInside
Browse files Browse the repository at this point in the history
  • Loading branch information
domi-b committed Jan 18, 2024
2 parents 92b3e8f + 035d14f commit ae060a8
Show file tree
Hide file tree
Showing 12 changed files with 43 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@
import java.util.stream.Stream;

public abstract class BaseIsInsideFunction extends BaseInterlisFunction {
protected final Value isInsideValidArea(String usageScope, Collection<IomObject> testObjects, String geometryAttribute, Supplier<Geometry> validAreaSupplier) {
protected final Value isInsideValidArea(String usageScope, Value testObjects, Value geometryAttribute, Supplier<Geometry> validAreaSupplier) {
try {
Geometry validArea = validAreaSupplier.get();

if (validArea == null) {
return Value.createUndefined();
}

boolean allInsideValidArea = testObjects.stream()
.flatMap(obj -> getAttributes(obj, geometryAttribute).stream())
Collection<IomObject> geometries = EvaluationHelper.evaluateObjectPath(td, validator, testObjects, geometryAttribute, null, usageScope);

boolean allInsideValidArea = geometries.stream()
.map(geometry -> logExceptionAsWarning(() -> geometry2JtsOrNull(geometry)))
.filter(Objects::nonNull)
.allMatch(validArea::contains);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,24 @@ public static Collection<IomObject> evaluateAttributes(Validator validator, Valu
return attributes;
}

/**
* Get the collection of {@link IomObject} inside {@code object} by following the provided {@code path} text.
* If the {@code path} is UNDEFINED, the direct collection of {@code object} is returned.
*/
public static Collection<IomObject> evaluateObjectPath(TransferDescription td, Validator validator, Value object, Value path, IomObject contextObject, String usageScope) {
if (path.isUndefined()) {
return object.getComplexObjects();
} else {
Viewable contextClass = EvaluationHelper.getContextClass(td, contextObject, object);
if (contextClass == null) {
throw new IllegalStateException("unknown class in " + usageScope);
}

PathEl[] attributePath = EvaluationHelper.getAttributePathEl(validator, contextClass, path);
return EvaluationHelper.evaluateAttributes(validator, object, attributePath);
}
}

/**
* Applies the given function to each item in the collection and sums up the results.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package ch.geowerkstatt.ilivalidator.extensions.functions;

import ch.interlis.ili2c.metamodel.PathEl;
import ch.interlis.ili2c.metamodel.Viewable;
import ch.interlis.iom.IomObject;
import ch.interlis.iox.IoxException;
import ch.interlis.iox_j.jts.Iox2jtsext;
Expand Down Expand Up @@ -38,20 +36,7 @@ public Value evaluateInternal(String validationKind, String usageScope, IomObjec
return Value.createUndefined();
}

Collection<IomObject> surfaces;

if (argPath.isUndefined()) {
surfaces = argObjects.getComplexObjects();
} else {
Viewable contextClass = EvaluationHelper.getContextClass(td, contextObject, argObjects);

if (contextClass == null) {
throw new IllegalStateException("unknown class in " + usageScope);
}

PathEl[] attributePath = EvaluationHelper.getAttributePathEl(validator, contextClass, argPath);
surfaces = EvaluationHelper.evaluateAttributes(validator, argObjects, attributePath);
}
Collection<IomObject> surfaces = EvaluationHelper.evaluateObjectPath(td, validator, argObjects, argPath, contextObject, usageScope);

double areaSum = EvaluationHelper.sum(surfaces, this::getArea);
return new Value(areaSum);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package ch.geowerkstatt.ilivalidator.extensions.functions;

import ch.interlis.ili2c.metamodel.PathEl;
import ch.interlis.ili2c.metamodel.Viewable;
import ch.interlis.iom.IomObject;
import ch.interlis.iox_j.validator.Value;

Expand Down Expand Up @@ -38,20 +36,7 @@ public Value evaluateInternal(String validationKind, String usageScope, IomObjec
return Value.createUndefined();
}

Collection<IomObject> surfaces;

if (argPath.isUndefined()) {
surfaces = argObjects.getComplexObjects();
} else {
Viewable contextClass = EvaluationHelper.getContextClass(td, contextObject, argObjects);

if (contextClass == null) {
throw new IllegalStateException("unknown class in " + usageScope);
}

PathEl[] attributePath = EvaluationHelper.getAttributePathEl(validator, contextClass, argPath);
surfaces = EvaluationHelper.evaluateAttributes(validator, argObjects, attributePath);
}
Collection<IomObject> surfaces = EvaluationHelper.evaluateObjectPath(td, validator, argObjects, argPath, contextObject, usageScope);

int innerRingsCount = surfaces.stream().map(this::getInnerRingsCount).reduce(0, Integer::sum);
return new Value(innerRingsCount);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package ch.geowerkstatt.ilivalidator.extensions.functions;

import ch.interlis.ili2c.metamodel.PathEl;
import ch.interlis.ili2c.metamodel.Viewable;
import ch.interlis.iom.IomObject;
import ch.interlis.iox.IoxException;
import ch.interlis.iox_j.jts.Iox2jtsext;
Expand Down Expand Up @@ -38,20 +36,7 @@ public Value evaluateInternal(String validationKind, String usageScope, IomObjec
return Value.createUndefined();
}

Collection<IomObject> polylines;

if (argPath.isUndefined()) {
polylines = argObjects.getComplexObjects();
} else {
Viewable contextClass = EvaluationHelper.getContextClass(td, contextObject, argObjects);

if (contextClass == null) {
throw new IllegalStateException("unknown class in " + usageScope);
}

PathEl[] attributePath = EvaluationHelper.getAttributePathEl(validator, contextClass, argPath);
polylines = EvaluationHelper.evaluateAttributes(validator, argObjects, attributePath);
}
Collection<IomObject> polylines = EvaluationHelper.evaluateObjectPath(td, validator, argObjects, argPath, contextObject, usageScope);

double lengthSum = EvaluationHelper.sum(polylines, this::getLength);
return new Value(lengthSum);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,15 @@ protected Value evaluateInternal(String validationKind, String usageScope, IomOb
Value argTestObject = arguments[2]; // OBJECT OF ANYCLASS
Value argTestObjectgeometry = arguments[3]; // TEXT

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

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

return isInsideValidArea(usageScope, argTestObject.getComplexObjects(), testObjectGeometryAttribute, () -> VALID_AREA_CACHE.computeIfAbsent(key, this::getValidArea));
return isInsideValidArea(usageScope, argTestObject, argTestObjectgeometry, () -> VALID_AREA_CACHE.computeIfAbsent(key, this::getValidArea));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,16 @@ protected Value evaluateInternal(String validationKind, String usageScope, IomOb
Value argTestObject = arguments[3]; // OBJECT OF ANYCLASS
Value argTestObjectgeometry = arguments[4]; // TEXT

if (argTransferFile.isUndefined() || argDatasetName.isUndefined() || argObjects.isUndefined() || argTestObject.isUndefined() || argTestObjectgeometry.isUndefined()) {
if (argTransferFile.isUndefined() || argDatasetName.isUndefined() || argObjects.isUndefined() || argTestObject.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, argTestObject.getComplexObjects(), testObjectGeometryAttribute, () -> VALID_AREA_CACHE.computeIfAbsent(key, this::getValidArea));
return isInsideValidArea(usageScope, argTestObject, argTestObjectgeometry, () -> VALID_AREA_CACHE.computeIfAbsent(key, this::getValidArea));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,28 @@ public String getQualifiedIliName() {

@Override
protected Value evaluateInternal(String validationKind, String usageScope, IomObject mainObj, Value[] arguments) {
Value argReferenceGeometry = arguments[0]; // MULTIAREA
Value argTestObject = arguments[1]; // OBJECT OF ANYCLASS
Value argTestObjectgeometry = arguments[2]; // TEXT
Value argReferenceObject = arguments[0]; // ANYSTRUCTURE
Value argReferenceGeometryPath = arguments[1]; // TEXT
Value argTestObject = arguments[2]; // OBJECT OF ANYCLASS
Value argTestObjectgeometry = arguments[3]; // TEXT

if (argTestObject.isUndefined() || argTestObjectgeometry.isUndefined()) {
return Value.createSkipEvaluation();
}
if (argReferenceGeometry.isUndefined()) {
if (argReferenceObject.isUndefined()) {
writeLogErrorMessage(usageScope, "Missing reference geometry.");
return Value.createUndefined();
}

Collection<IomObject> referenceGeometryObjects = argReferenceGeometry.getComplexObjects();
Collection<IomObject> referenceGeometryObjects = EvaluationHelper.evaluateObjectPath(td, validator, argReferenceObject, argReferenceGeometryPath, mainObj, usageScope);
if (referenceGeometryObjects.size() != 1) {
writeLogErrorMessage(usageScope, "Expected exactly one reference geometry.");
return Value.createUndefined();
}

IomObject referenceGeometry = referenceGeometryObjects.iterator().next();
String testObjectGeometryAttribute = argTestObjectgeometry.getValue();

return isInsideValidArea(usageScope, argTestObject.getComplexObjects(), testObjectGeometryAttribute, () -> VALID_AREA_CACHE.computeIfAbsent(referenceGeometry, this::getValidArea));
return isInsideValidArea(usageScope, argTestObject, argTestObjectgeometry, () -> VALID_AREA_CACHE.computeIfAbsent(referenceGeometry, this::getValidArea));
}

private Geometry getValidArea(IomObject referenceGeometry) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package ch.geowerkstatt.ilivalidator.extensions.functions;

import ch.interlis.ili2c.metamodel.PathEl;
import ch.interlis.ili2c.metamodel.Viewable;
import ch.interlis.iom.IomObject;
import ch.interlis.iom_j.itf.impl.jtsext.geom.CompoundCurve;
import ch.interlis.iox.IoxException;
Expand Down Expand Up @@ -39,19 +37,7 @@ protected Value evaluateInternal(String validationKind, String usageScope, IomOb
return Value.createUndefined();
}

Collection<IomObject> polylineObjects;

if (argPath.isUndefined()) {
polylineObjects = argObjects.getComplexObjects();
} else {
Viewable contextClass = EvaluationHelper.getContextClass(td, contextObject, argObjects);
if (contextClass == null) {
throw new IllegalStateException("unknown class in " + usageScope);
}

PathEl[] attributePath = EvaluationHelper.getAttributePathEl(validator, contextClass, argPath);
polylineObjects = EvaluationHelper.evaluateAttributes(validator, argObjects, attributePath);
}
Collection<IomObject> polylineObjects = EvaluationHelper.evaluateObjectPath(td, validator, argObjects, argPath, contextObject, usageScope);

Collection<IomObject> inputObjects = argObjects.getComplexObjects();
List<String> objectIds = inputObjects.stream().map(IomObject::getobjectoid).collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package ch.geowerkstatt.ilivalidator.extensions.functions;

import ch.ehi.basics.types.OutParam;
import ch.interlis.ili2c.metamodel.PathEl;
import ch.interlis.ili2c.metamodel.Viewable;
import ch.interlis.iom.IomObject;
import ch.interlis.iox.IoxException;
import ch.interlis.iox_j.jts.Iox2jtsException;
Expand Down Expand Up @@ -38,19 +36,7 @@ protected Value evaluateInternal(String validationKind, String usageScope, IomOb
return Value.createSkipEvaluation();
}

Collection<IomObject> surfaces;
if (argPath.isUndefined()) {
surfaces = argObjects.getComplexObjects();
} else {
Viewable contextClass = EvaluationHelper.getContextClass(td, contextObject, argObjects);
if (contextClass == null) {
throw new IllegalStateException("unknown class in " + usageScope);
}

PathEl[] attributePath = EvaluationHelper.getAttributePathEl(validator, contextClass, argPath);
surfaces = EvaluationHelper.evaluateAttributes(validator, argObjects, attributePath);
}

Collection<IomObject> surfaces = EvaluationHelper.evaluateObjectPath(td, validator, argObjects, argPath, contextObject, usageScope);
if (surfaces == null) {
return Value.createUndefined();
}
Expand Down
4 changes: 2 additions & 2 deletions src/model/GeoW_FunctionsExt.ili
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ MODEL GeoW_FunctionsExt
FUNCTION IsInsideExternalDatasetResource (TransferFile: TEXT; DatasetName: TEXT; Objects: TEXT; TestObject: OBJECT OF ANYCLASS; TestObjectgeometry: TEXT): BOOLEAN;

!!@ fn.description = "Prüft, ob ein Objekt innerhalb der Geometrie eines anderen Objektes liegt.";
!!@ fn.param = "ReferenceGeometry: Referenzgeometrie, innerhalb welcher das TestObject liegen muss. TestObject: Objekt, welches zu prüfen ist. TestObjectgeometry: Geometriefeld, bezogen auf das unter Testobject übergebene Objekt";
!!@ fn.param = "ReferenceObject: Referenzobjekt oder -geometrie, innerhalb welcher das TestObject liegen muss. ReferenceGeometryAttr: Pfad zum Geometrieattribut vom Referenzobjekt oder UNDEFINED. TestObject: Objekt, welches zu prüfen ist. TestObjectgeometry: Geometriefeld, bezogen auf das unter Testobject übergebene Objekt";
!!@ fn.return = "Boolean";
!!@ fn.since = "2023-12-21";
FUNCTION IsInside (ReferenceGeometry: MULTIAREA; TestObject: OBJECT OF ANYCLASS; TestObjectgeometry: TEXT): BOOLEAN;
FUNCTION IsInside (ReferenceObject: ANYSTRUCTURE; ReferenceGeometryAttr: 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 'Objects' können Objekte oder Geometrien angegeben werden. Für 'GeometryAttr' soll der Pfad zur Flächen-Geometrie in INTERLIS 2 Syntax angegeben werden. Falls 'Objects' bereits die Geometrien enthält, soll für 'GeometryAttr' 'UNDEFINED' übergeben werden.";
!!@ fn.param = "Objects: Objekte, deren Geometrien zusammengefasst werden sollen. GeometryAttr: Pfad zum Geometrieattribut oder UNDEFINED";
Expand Down
5 changes: 3 additions & 2 deletions src/test/data/IsInside/MandatoryConstraintThis.ili
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ MODEL TestSuite
CLASS IsInsideKantonsgrenze EXTENDS ConstraintTestClass =
testAttributeIsInsideKantonsgrenze : CHKoord;
testAttributeKantonsgrenze : CHMultiArea;
MANDATORY CONSTRAINT IsInsideKantonsgrenze: GeoW_FunctionsExt.IsInside(THIS->testAttributeKantonsgrenze, THIS, "testAttributeIsInsideKantonsgrenze") == expected;
MANDATORY CONSTRAINT IsInsideKantonsgrenzePath: GeoW_FunctionsExt.IsInside(THIS, "testAttributeKantonsgrenze", THIS, "testAttributeIsInsideKantonsgrenze") == expected;
MANDATORY CONSTRAINT IsInsideKantonsgrenzeUndefinedPath: GeoW_FunctionsExt.IsInside(THIS->testAttributeKantonsgrenze, UNDEFINED, THIS->testAttributeIsInsideKantonsgrenze, UNDEFINED) == expected;
END IsInsideKantonsgrenze;

CLASS InvalidConstraints =
geometryAttribute : CHKoord;
area : CHMultiArea;
MANDATORY CONSTRAINT IsInsideMissingArea: GeoW_FunctionsExt.IsInside(THIS->area, THIS, "geometryAttribute");
MANDATORY CONSTRAINT IsInsideMissingArea: GeoW_FunctionsExt.IsInside(THIS->area, UNDEFINED, THIS, "geometryAttribute");
END InvalidConstraints;

END FunctionTestTopic;
Expand Down

0 comments on commit ae060a8

Please sign in to comment.