Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add geometry attribute parameter to IsInside #45

Merged
merged 2 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading