import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
import org.simantics.Simantics;
+import org.simantics.databoard.Bindings;
import org.simantics.db.ReadGraph;
+import org.simantics.db.RequestProcessor;
import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
import org.simantics.db.common.request.ResourceRead;
import org.simantics.db.common.utils.ListUtils;
+import org.simantics.db.exception.AssumptionException;
import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.DoesNotContainValueException;
+import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
+import org.simantics.db.exception.NoSingleResultException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.db.exception.ValidationException;
+import org.simantics.db.layer0.QueryIndexUtils;
import org.simantics.db.layer0.request.ActiveModels;
import org.simantics.db.layer0.request.ActiveRuns;
import org.simantics.db.layer0.request.Configuration;
+import org.simantics.db.layer0.request.PossibleActiveModel;
import org.simantics.db.layer0.variable.RVI;
import org.simantics.db.layer0.variable.Variable;
import org.simantics.db.layer0.variable.Variables;
+import org.simantics.db.request.Read;
import org.simantics.diagram.stubs.DiagramResource;
import org.simantics.district.network.ontology.DistrictNetworkResource;
import org.simantics.district.region.ontology.DiagramRegionsResource;
-import org.simantics.district.selection.ElementSelector.AggregateCondition.Type;
import org.simantics.layer0.Layer0;
import org.simantics.modeling.ModelingResources;
-import org.simantics.scl.runtime.Lists;
-import org.simantics.scl.runtime.function.FunctionImpl1;
-import org.simantics.scl.runtime.tuple.Tuple2;
import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.utils.datastructures.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ElementSelector {
String name;
String expression;
- Integer count;
+
Resource resource;
Generator generator;
Selector selector;
Condition condition;
+ private float[] color;
+
static Logger LOG = LoggerFactory.getLogger(ElementSelector.class);
static ElementSelectionResource ES;
static DiagramResource DIA;
static DistrictNetworkResource DN;
+ private static Logger LOGGER = LoggerFactory.getLogger(ElementSelector.class);
+
ElementSelector(ReadGraph graph, Resource resource) throws DatabaseException {
super();
DN = DistrictNetworkResource.getInstance(graph);
this.resource = resource;
- this.count = -1;
try {
this.name = graph.getRelatedValue(resource, L0.HasLabel);
- this.expression = buildExpression(graph, resource);
+ this.expression = getExpression(graph, resource);
+
+ float[] color = graph.getPossibleRelatedValue(resource, ES.Selection_HasHighlightColor);
+ this.color = color;
} catch (DatabaseException e) {
LOG.error("Error reading element selector", e);
throw e;
}
}
- public static ElementSelector getSelector(ReadGraph graph, Resource resource) throws DatabaseException {
+ /**
+ * Instantiate an element selector object for an ES.Selection resource.
+ */
+ public static ElementSelector getSelector(RequestProcessor graph, Resource resource) throws DatabaseException {
return graph.syncRequest(new ElementSelectorQuery(resource));
}
+
+ /**
+ * Get an SQL-like textual description of an ES.Selection resource.
+ */
+ public static String getExpression(RequestProcessor graph, Resource resource) throws DatabaseException {
+ return graph.syncRequest(new SelectionExpressionRequest(resource));
+ }
+ /**
+ * Get a Java object representation of an ES.Condition resource.
+ */
+ public static Condition getCondition(RequestProcessor graph, Resource condition) throws DatabaseException {
+ return graph.syncRequest(new SelectionConditionRequest(condition));
+ }
+
+ /**
+ * Get the name of the element selector.
+ */
public String getName() {
return name;
}
+ /**
+ * Get a textual SQL-like description of the element selector.
+ */
public String getExpression() {
return expression;
}
+ /**
+ * Get the resource that this selector represents.
+ */
public Resource getResource() {
return resource;
}
- public List<Resource> selectElementsFrom(ReadGraph graph, Resource model) throws DatabaseException {
+ /**
+ * Get the generator component. Use {@link #buildSelection(ReadGraph)} to make it available first.
+ */
+ public Generator getGenerator() {
+ return generator;
+ }
+
+ /**
+ * Get the selector component. Use {@link #buildSelection(ReadGraph)} to make it available first.
+ */
+ public Selector getSelector() {
+ return selector;
+ }
+
+ /**
+ * Get the condition component. Use {@link #buildSelection(ReadGraph)} to make it available first.
+ */
+ public Condition getCondition() {
+ return condition;
+ }
+
+ /**
+ * Get the selection highlight color as a four element BGRA array.
+ */
+ public float[] getColor() {
+ return color;
+ }
+
+ /**
+ *
+ * @param graph
+ * @throws DatabaseException
+ */
+ public void buildSelection(ReadGraph graph) throws DatabaseException {
+ Resource selector = graph.getSingleObject(resource, ES.Selection_HasSelector);
+ Resource generator = graph.getSingleObject(resource, ES.Selection_HasGenerator);
+ Resource condition = graph.getPossibleObject(resource, ES.Selection_HasCondition);
+
+ this.selector = buildSelector(graph, selector);
+ this.generator = buildGenerator(graph, generator);
+ this.condition = buildCondition(graph, condition);
+ }
+
+ public static Map<Resource, String> findDiagrams() {
+ try {
+ return Simantics.getSession().syncRequest(new Read<Map<Resource, String>>() {
+ @Override
+ public Map<Resource, String> perform(ReadGraph graph) throws DatabaseException {
+ Layer0 L0 = Layer0.getInstance(graph);
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);
+ DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
+ ModelingResources MOD = ModelingResources.getInstance(graph);
+
+ Map<Resource, String> result = new HashMap<>();
+ Resource model = graph.syncRequest(new PossibleActiveModel(Simantics.getProjectResource()));
+ List<Resource> composites = QueryIndexUtils.searchByType(graph, model, STR.Composite);
+ for (Resource r : composites) {
+ // Get diagram
+ Resource diagram = graph.getPossibleObject(r, MOD.CompositeToDiagram);
+ if (diagram == null || !graph.isInstanceOf(diagram, DN.Diagram))
+ continue;
+
+ // Filter out user component diagrams
+ Resource parent = graph.getPossibleObject(r, L0.PartOf);
+ if (parent == null || graph.isInheritedFrom(parent, STR.Component))
+ continue;
+
+ result.put(r, graph.getRelatedValue(r, L0.HasName));
+ }
+
+ return result;
+ }
+ });
+ } catch (DatabaseException e) {
+ LOGGER.error("Query for model diagrams failed", e);
+ return Collections.emptyMap();
+ }
+ }
+
+ public static Variable getVariableForElement(ReadGraph graph, Resource element) throws DatabaseException {
+ Resource component = graph.getPossibleObject(element, MOD.ElementToComponent);
+ if (component != null) {
+ Variable var = Variables.getVariable(graph, component);
+ RVI realRvi = var.getRVI(graph);
+
+ for (Resource activeModel : graph.syncRequest(new ActiveModels(Simantics.getProjectResource()))) {
+ for (Variable run : graph.syncRequest(new ActiveRuns(activeModel))) {
+ Variable v = realRvi.resolvePossible(graph, run);
+ if (v != null) {
+ return v;
+ }
+ }
+ Variable configuration = Variables.getPossibleConfigurationContext(graph, activeModel);
+ if (configuration != null) {
+ Variable v = realRvi.resolvePossible(graph, configuration);
+ if (v != null) {
+ return v;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public static Double getPropertyValue(ReadGraph graph, Resource element, String propertyName) {
+ try {
+ Variable v = getVariableForElement(graph, element);
+ if (v != null) {
+ Number value = v.getPossiblePropertyValue(graph, propertyName);
+ if (value != null)
+ return value.doubleValue();
+ }
+
+ // No property found - try possible mapped element property as well
+ Resource mappedElement = graph.getPossibleObject(element, DN.MappedComponent);
+ if (mappedElement != null)
+ return getPropertyValue(graph, mappedElement, propertyName);
+ }
+ catch (DatabaseException e) {
+ }
+
+ return null;
+ }
+
+ public SelectionResult selectElementsFrom(ReadGraph graph, Resource model) throws DatabaseException {
if (selector == null) {
buildSelection(graph);
}
- Collection<Resource> result = gather(graph, model);
- return result instanceof List ? (List<Resource>) result : new ArrayList<>(result);
+ return gather(graph, model);
}
private static Generator buildGenerator(ReadGraph graph, Resource resource) throws DatabaseException {
if (!graph.isInstanceOf(resource, ES.Generator))
throw new IllegalArgumentException("Resource " + resource + " is not a valid generator");
- if (graph.isInstanceOf(resource, ES.Generator_Model)) {
+ if (graph.isInstanceOf(resource, ES.Generator_Model))
return new ModelGenerator();
- }
- else if (graph.isInstanceOf(resource, ES.Generator_Diagram)) {
+ else if (graph.isInstanceOf(resource, ES.Generator_Diagram))
return new DiagramGenerator(graph.getSingleObject(resource, ES.Generator_HasDiagram));
- }
- else if (graph.isInstanceOf(resource, ES.Generator_Explicit)) {
+ else if (graph.isInstanceOf(resource, ES.Generator_Explicit))
return new ExplicitGenerator(graph.getObjects(resource, ES.Generator_HasSelectedElement));
- }
- else {
+ else
throw new IllegalArgumentException("Unknown generator type " + graph.getURI(graph.getSingleType(resource)));
- }
}
private static Selector buildSelector(ReadGraph graph, Resource resource) throws DatabaseException {
throw new IllegalArgumentException("Resource " + resource + " is not a valid selector");
Selector s;
- if (graph.isInstanceOf(resource, ES.Selector_All)) {
+ if (graph.isInstanceOf(resource, ES.Selector_All))
s = new All();
- }
- else if (graph.isInstanceOf(resource, ES.PropertySelector)) {
- String propertyName = graph.getRelatedValue(resource, ES.PropertySelector_HasSelectionPropertyName);
- Integer resultCount = graph.getRelatedValue(resource, ES.PropertySelector_HasResultCount);
- boolean isSmallest = graph.isInstanceOf(resource, ES.Selector_NLowest);
- s = new PropertySelector(isSmallest, propertyName, resultCount);
- }
- else {
+ else if (graph.isInstanceOf(resource, ES.PropertySelector))
+ s = new PropertySelector(graph, resource);
+ else
throw new IllegalArgumentException("Unknown selector type " + graph.getURI(graph.getSingleType(resource)));
- }
+
+ Resource mapping = graph.getPossibleObject(resource, ES.Selector_HasMapping);
+ s.componentType = mapping;
+
return s;
}
throw new IllegalArgumentException("Resource " + resource + " is not a valid condition");
Condition cond;
- if (graph.isInstanceOf(resource, ES.PropertyCondition)) {
- String propertyName = graph.getRelatedValue(resource, ES.PropertyCondition_HasPropertyName);
- Double lowerLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasLowerLimit);
- Double upperLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasUpperLimit);
- cond = new PropertyCondition(propertyName, lowerLimit, upperLimit);
+ if (graph.isInstanceOf(resource, ES.PropertyCondition))
+ cond = new PropertyCondition(graph, resource);
+ else if (graph.isInstanceOf(resource, ES.RegionCondition))
+ cond = new RegionCondition(graph, resource);
+ else if (graph.isInstanceOf(resource, ES.RouteCondition))
+ cond = new RouteCondition(graph, resource);
+ else if (graph.isInstanceOf(resource, ES.AggregateCondition))
+ cond = new AggregateCondition(graph, resource);
+ else
+ throw new IllegalArgumentException("Unknown condition type " + graph.getURI(graph.getSingleType(resource)));
+
+ return cond;
+ }
+
+ private static String buildExpression(ReadGraph graph, Resource r) throws DatabaseException {
+ if (graph.isInstanceOf(r, ES.Selection))
+ return buildSelectionExpression(graph, r);
+ else if (graph.isInstanceOf(r, ES.Condition))
+ return buildConditionExpression(graph, r);
+ else if (graph.isInstanceOf(r, ES.Selector))
+ return buildSelectorExpression(graph, r);
+ else if (graph.isInstanceOf(r, ES.Generator))
+ return buildGeneratorExpression(graph, r);
+ else
+ throw new DatabaseException("Unsupported resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
+ }
+
+ private static String buildSelectionExpression(ReadGraph graph, Resource r) throws DatabaseException,
+ NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException {
+ String exp = "select " + getExpression(graph, graph.getSingleObject(r, ES.Selection_HasSelector)) +
+ " from " + getExpression(graph, graph.getSingleObject(r, ES.Selection_HasGenerator));
+
+ Resource cond = graph.getPossibleObject(r, ES.Selection_HasCondition);
+ return cond != null ? exp + " where {" + getExpression(graph, cond) + "}" : exp;
+ }
+
+ private static String buildGeneratorExpression(ReadGraph graph, Resource r)
+ throws ServiceException, NoSingleResultException, DoesNotContainValueException,
+ ManyObjectsForFunctionalRelationException, DatabaseException, AssumptionException, ValidationException {
+ if (graph.isInstanceOf(r, ES.Generator_Model)) {
+ return "model";
}
- else if (graph.isInstanceOf(resource, ES.RegionCondition)) {
- DiagramRegionsResource DR = DiagramRegionsResource.getInstance(graph);
- double[] region = graph.getRelatedValue(graph.getSingleObject(resource, ES.RegionCondition_HasRegion), DR.Region_area);
- cond = new RegionCondition(region);
+ else if (graph.isInstanceOf(r, ES.Generator_Diagram)) {
+ return "diagram \"" + graph.getRelatedValue(graph.getSingleObject(r, ES.Generator_HasDiagram), L0.HasName) + "\"";
}
- else if (graph.isInstanceOf(resource, ES.RouteCondition)) {
- Set<Resource> routePoints = new HashSet<>(ListUtils.toList(graph, graph.getSingleObject(resource, ES.RouteCondition_HasRoute)));
- cond = new RouteCondition(routePoints);
+ else if (graph.isInstanceOf(r, ES.Generator_Explicit)) {
+ return "<list of " + graph.getObjects(r, ES.Generator_HasSelectedElement).size() + " elements>";
}
- else if (graph.isInstanceOf(resource, ES.AggregateCondition)) {
- boolean isDisjunction = graph.isInstanceOf(resource, ES.Disjunction);
- Collection<Resource> conditionResources = graph.getObjects(resource, ES.HasSubcondition);
- List<Condition> conditions = new ArrayList<>(conditionResources.size());
- for (Resource c : conditionResources) {
- conditions.add(buildCondition(graph, c));
- }
- Type type;
- if (graph.isInstanceOf(resource, ES.Conjunction))
- type = AggregateCondition.Type.CONJUNCTION;
- else if (graph.isInstanceOf(resource, ES.Negation))
- type = AggregateCondition.Type.NEGATION;
- else if (graph.isInstanceOf(resource, ES.Disjunction))
- type = AggregateCondition.Type.DISJUNCTION;
- else
- throw new IllegalArgumentException("Unknown aggreate condition type " + graph.getURI(graph.getSingleType(resource)));
-
- cond = new AggregateCondition(type, conditions);
+ else {
+ throw new DatabaseException("Unsupported generator resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
+ }
+ }
+
+ private static String buildSelectorExpression(ReadGraph graph, Resource r)
+ throws ServiceException, NoSingleResultException, DoesNotContainValueException, DatabaseException,
+ AssumptionException, ValidationException, ManyObjectsForFunctionalRelationException {
+ String exp;
+ if (graph.isInstanceOf(r, ES.Selector_All)) {
+ exp = "all";
+ }
+ else if (graph.isInstanceOf(r, ES.PropertySelector)) {
+ Integer count = graph.getRelatedValue(r, ES.PropertySelector_HasResultCount);
+ exp = count.toString();
}
else {
- throw new IllegalArgumentException("Unknown condition type " + graph.getURI(graph.getSingleType(resource)));
+ throw new DatabaseException("Unsupported selector resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
}
- cond.isInverse = graph.hasStatement(resource, ES.Condition_IsInverse, resource);
- return cond;
+ Resource mapping = graph.getPossibleObject(r, ES.Selector_HasMapping);
+ if (mapping != null) {
+ String name = graph.getRelatedValue2(mapping, L0.HasName);
+ exp = exp + " " + name;
+ } else {
+ exp = exp + " elements";
+ }
+
+ if (graph.isInstanceOf(r, ES.PropertySelector)) {
+ String op;
+ if (graph.isInstanceOf(r, ES.Selector_NLowest))
+ op = "lowest";
+ else if (graph.isInstanceOf(r, ES.Selector_NHighest))
+ op = "highest";
+ else
+ throw new DatabaseException("Unsupported property selector resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
+
+ String name = graph.getRelatedValue(r, ES.PropertySelector_HasSelectionPropertyName);
+ exp = exp + " with " + op + " " + name;
+ }
+
+ return exp;
}
- private static String buildExpression(ReadGraph graph, Resource r) throws DatabaseException {
- if (graph.isInstanceOf(r, ES.Selection)) {
- String exp = "select " + buildExpression(graph, graph.getSingleObject(r, ES.Selection_HasSelector)) +
- " from " + buildExpression(graph, graph.getSingleObject(r, ES.Selection_HasGenerator));
-
- Resource cond = graph.getPossibleObject(r, ES.Selection_HasCondition);
- return cond != null ? exp + " where {" + buildExpression(graph, cond) + "}" : exp;
+ private static String buildConditionExpression(ReadGraph graph, Resource r) throws ServiceException,
+ DatabaseException, NoSingleResultException, ManyObjectsForFunctionalRelationException,
+ DoesNotContainValueException, AssumptionException, ValidationException {
+ String result;
+ boolean isInverse = graph.hasStatement(r, ES.Condition_IsInverse, r);
+ if (graph.isInstanceOf(r, ES.PropertyCondition)) {
+ result = buildPropertyConditionExpression(graph, r);
}
- else if (graph.isInstanceOf(r, ES.Condition)) {
- if (graph.isInstanceOf(r, ES.PropertyCondition)) {
- return buildPropertyConditionExpression(graph, r);
- }
- else if (graph.isInstanceOf(r, ES.RegionCondition)) {
- Resource region = graph.getSingleObject(r, ES.RegionCondition_HasRegion);
- String name = graph.getRelatedValue(region, L0.HasLabel);
- return "in region " + name;
- }
- else if (graph.isInstanceOf(r, ES.RouteCondition)) {
- Resource route = graph.getSingleObject(r, ES.RouteCondition_HasRoute);
- String name = graph.getRelatedValue(route, L0.HasLabel);
- return "in route " + name;
- }
- else if (graph.isInstanceOf(r, ES.AggregateCondition)) {
- String op = graph.isInstanceOf(r, ES.Conjunction) ? " and " : " or ";
- List<String> exps = new ArrayList<>();
- Collection<Resource> objects = graph.getObjects(r, ES.HasSubcondition);
- for (Resource c : objects) {
- String exp = buildExpression(graph, c);
- exps.add(objects.size() > 1 ? "{" + exp + "}" : exp);
- }
- String result = String.join(op, exps);
- if (graph.isInstanceOf(r, ES.Negation))
- result = "not {" + result + "}";
- return result;
- }
- else {
- throw new DatabaseException("Unsupported condition resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
- }
+ else if (graph.isInstanceOf(r, ES.RegionCondition)) {
+ result = buildRegionConditionExpression(graph, r);
}
- else if (graph.isInstanceOf(r, ES.Selector)) {
- if (graph.isInstanceOf(r, ES.Selector_All)) {
- return "all";
- }
- else if (graph.isInstanceOf(r, ES.PropertySelector)) {
- String op;
- if (graph.isInstanceOf(r, ES.Selector_NLowest))
- op = "bottom";
- else if (graph.isInstanceOf(r, ES.Selector_NHighest))
- op = "top";
- else
- throw new DatabaseException("Unsupported property selector resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
-
- String name = graph.getRelatedValue(r, ES.PropertySelector_HasSelectionPropertyName);
- Integer count = graph.getRelatedValue(r, ES.PropertySelector_HasResultCount);
- return op + " " + count + " of " + name;
- }
- else {
- throw new DatabaseException("Unsupported selector resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
- }
+ else if (graph.isInstanceOf(r, ES.RouteCondition)) {
+ result = buildRouteConditionExpression(graph, r);
}
- else if (graph.isInstanceOf(r, ES.Generator)) {
- if (graph.isInstanceOf(r, ES.Generator_Model)) {
- return "model";
- }
- else if (graph.isInstanceOf(r, ES.Generator_Diagram)) {
- return "diagram \"" + graph.getRelatedValue(graph.getSingleObject(r, ES.Generator_HasDiagram), L0.HasName) + "\"";
- }
- else if (graph.isInstanceOf(r, ES.Generator_Explicit)) {
- return "<list of " + graph.getObjects(r, ES.Generator_HasSelectedElement).size() + " elements>";
- }
- else {
- throw new DatabaseException("Unsupported generator resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
- }
+ else if (graph.isInstanceOf(r, ES.AggregateCondition)) {
+ // This handles isInverse internally
+ return buildAggregateConditionExpression(graph, r, isInverse);
}
else {
- throw new DatabaseException("Unsupported resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
+ throw new DatabaseException("Unsupported condition resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
}
+
+ if (isInverse)
+ result = "not {" + result + "}";
+
+ return result;
+ }
+
+ private static String buildAggregateConditionExpression(ReadGraph graph, Resource r, boolean isInverse)
+ throws ServiceException, DatabaseException {
+ String result;
+ String op = graph.isInstanceOf(r, ES.Conjunction) ? " and " : " or ";
+ List<String> exps = new ArrayList<>();
+ Collection<Resource> objects = graph.getObjects(r, ES.HasSubcondition);
+ for (Resource c : objects) {
+ String exp = getExpression(graph, c);
+ exps.add(objects.size() > 1 ? "{" + exp + "}" : exp);
+ }
+ result = String.join(op, exps);
+ if (graph.isInstanceOf(r, ES.Negation) ^ isInverse)
+ result = "not {" + result + "}";
+ return result;
+ }
+
+ private static String buildRouteConditionExpression(ReadGraph graph, Resource r) throws NoSingleResultException,
+ ManyObjectsForFunctionalRelationException, ServiceException, DoesNotContainValueException {
+ String result;
+ Resource route = graph.getSingleObject(r, ES.RouteCondition_HasRoute);
+ String name = graph.getRelatedValue(route, L0.HasLabel);
+ result = "in route " + name;
+ return result;
+ }
+
+ private static String buildRegionConditionExpression(ReadGraph graph, Resource r) throws NoSingleResultException,
+ ManyObjectsForFunctionalRelationException, ServiceException, DoesNotContainValueException {
+ String result;
+ Resource region = graph.getSingleObject(r, ES.RegionCondition_HasRegion);
+ String name = graph.getRelatedValue(region, L0.HasLabel);
+ result = "in region " + name;
+ return result;
}
private static String buildPropertyConditionExpression(ReadGraph graph, Resource r) throws DatabaseException {
String propertyName = graph.getRelatedValue(r, ES.PropertyCondition_HasPropertyName);
Double lowerLimit = graph.getPossibleRelatedValue(r, ES.PropertyCondition_HasLowerLimit);
Double upperLimit = graph.getPossibleRelatedValue(r, ES.PropertyCondition_HasUpperLimit);
- if (lowerLimit == null && upperLimit == null) {
- return "has property " + propertyName;
- }
- else {
+ if (upperLimit == null) {
+ if (lowerLimit == null) {
+ return "has property " + propertyName;
+ } else {
+ return propertyName + " \u2265 " + lowerLimit;
+ }
+ } else {
StringBuilder result = new StringBuilder();
if (lowerLimit != null) {
result.append(lowerLimit);
- result.append(" < ");
+ result.append(" \u2264 ");
}
result.append(propertyName);
- if (upperLimit != null) {
- result.append(" < ");
- result.append(upperLimit);
- }
+ result.append(" \u2264 ");
+ result.append(upperLimit);
return result.toString();
}
}
return result;
}
- private void buildSelection(ReadGraph graph) throws DatabaseException {
- Resource selector = graph.getSingleObject(resource, ES.Selection_HasSelector);
- Resource generator = graph.getSingleObject(resource, ES.Selection_HasGenerator);
- Resource condition = graph.getPossibleObject(resource, ES.Selection_HasCondition);
-
- this.selector = buildSelector(graph, selector);
- this.generator = buildGenerator(graph, generator);
- this.condition = buildCondition(graph, condition);
- }
-
private Collection<Resource> filterElementsFrom(ReadGraph graph, Collection<Resource> elements) throws DatabaseException {
if (condition == null) return elements;
return result;
}
- private Collection<Resource> gather(ReadGraph graph, Resource model) throws DatabaseException {
+ private SelectionResult gather(ReadGraph graph, Resource model) throws DatabaseException {
return selector.select(graph, filterElementsFrom(graph, generator.generate(graph, model)));
}
- static Variable getVariableForElement(ReadGraph graph, Resource element) throws DatabaseException {
- Resource component = graph.getPossibleObject(element, MOD.ElementToComponent);
- if (component != null) {
- Variable var = Variables.getVariable(graph, component);
- RVI realRvi = var.getRVI(graph);
-
- for (Resource activeModel : graph.syncRequest(new ActiveModels(Simantics.getProjectResource()))) {
- for (Variable run : graph.syncRequest(new ActiveRuns(activeModel))) {
- Variable v = realRvi.resolvePossible(graph, run);
- if (v != null) {
- return v;
- }
- }
- Variable configuration = Variables.getPossibleConfigurationContext(graph, activeModel);
- if (configuration != null) {
- Variable v = realRvi.resolvePossible(graph, configuration);
- if (v != null) {
- return v;
- }
- }
- }
- }
-
- return null;
- }
-
- static Double getPropertyValue(ReadGraph graph, Resource element, String propertyName) {
- try {
- Variable v = getVariableForElement(graph, element);
- if (v != null) {
- Number value = v.getPossiblePropertyValue(graph, propertyName);
- if (value != null)
- return value.doubleValue();
- }
-
- // No property found - try possible mapped element property as well
- Resource mappedElement = graph.getPossibleObject(element, DN.MappedComponent);
- if (mappedElement != null)
- return getPropertyValue(graph, mappedElement, propertyName);
- }
- catch (DatabaseException e) {
- }
-
- return null;
- }
-
// Generators
- static abstract class Generator {
+ public static abstract class Generator {
abstract Collection<Resource> generate(ReadGraph graph, Resource model) throws DatabaseException;
}
- static class ModelGenerator extends Generator {
+ public static class ModelGenerator extends Generator {
@Override
Collection<Resource> generate(ReadGraph graph, Resource model) throws DatabaseException {
Resource conf = graph.syncRequest(new Configuration(model));
- ArrayList<Resource> result = new ArrayList<>();
+ HashMap<Resource, Resource> fromMapped = new HashMap<Resource, Resource>();
// Iterate over diagrams
+ // Each model element is represented by the corresponding mapping element, if present
for (Resource comp : graph.getObjects(conf, L0.ConsistsOf)) {
if (!graph.isInstanceOf(comp, STR.Composite)) continue;
Resource diagram = graph.getPossibleObject(comp, MOD.CompositeToDiagram);
- if (diagram != null) result.addAll(elementsOfDiagram(graph, diagram));
+ if (diagram != null) {
+ for (Resource elem : elementsOfDiagram(graph, diagram)) {
+ Resource mapped = graph.getPossibleObject(elem, DN.MappedComponent);
+ if (mapped != null) {
+ fromMapped.put(mapped, elem);
+ }
+ else if (!fromMapped.containsKey(elem)) {
+ fromMapped.put(elem, elem);
+ }
+ }
+ }
}
- return result;
+ return new ArrayList<>(fromMapped.values());
}
}
- static class DiagramGenerator extends Generator {
- Resource diagram;
+ public static class DiagramGenerator extends Generator {
+ public Resource diagram;
public DiagramGenerator(Resource diagram) {
this.diagram = diagram;
}
}
- static class ExplicitGenerator extends Generator {
+ public static class ExplicitGenerator extends Generator {
public ExplicitGenerator(Collection<Resource> elements) {
this.elements = elements;
}
- Collection<Resource> elements;
+ public Collection<Resource> elements;
@Override
Collection<Resource> generate(ReadGraph graph, Resource model) {
// Selectors
- static abstract class Selector {
- abstract Collection<Resource> select(ReadGraph graph, Collection<Resource> elements);
+ public static class SelectionResult {
+ public final Collection<Resource> elements;
+ public final int tailCount;
+ public final int tailSize;
+
+ public SelectionResult(Collection<Resource> elements, int tailCount, int tailSize) {
+ this.elements = elements;
+ this.tailCount = tailCount;
+ this.tailSize = tailSize;
+ }
+ }
+
+ public static abstract class Selector {
+ public Resource componentType = null;
+
+ abstract SelectionResult select(ReadGraph graph, Collection<Resource> elements);
+
+ Collection<Resource> filterElements(ReadGraph graph, Collection<Resource> elements) {
+ if (componentType == null)
+ return elements;
+
+ Collection<Resource> selected = new HashSet<>(elements.size());
+ for (Resource r : elements) {
+ try {
+ if (graph.hasStatement(r, DN.HasMapping, componentType))
+ selected.add(r);
+ } catch (DatabaseException e) {
+ // Just leave it out of the result
+ }
+ }
+
+ return selected;
+ }
}
- static class All extends Selector {
+ public static class All extends Selector {
public All() {
}
@Override
- Collection<Resource> select(ReadGraph graph, Collection<Resource> elements) {
- return elements;
+ SelectionResult select(ReadGraph graph, Collection<Resource> elements) {
+ Collection<Resource> selected = filterElements(graph, elements);
+ return new SelectionResult(selected, 0, 0);
}
}
- static class PropertySelector extends Selector {
+ public static class PropertySelector extends Selector {
public PropertySelector(boolean smallest, String propertyName, int resultCount) {
this.smallest = smallest;
this.propertyName = propertyName;
this.resultCount = resultCount;
}
- boolean smallest;
- String propertyName;
- int resultCount;
+ public PropertySelector(ReadGraph graph, Resource resource) throws DatabaseException {
+ this.propertyName = graph.getRelatedValue(resource, ES.PropertySelector_HasSelectionPropertyName);
+ this.resultCount = graph.getRelatedValue(resource, ES.PropertySelector_HasResultCount);
+ this.smallest = graph.isInstanceOf(resource, ES.Selector_NLowest);
+ }
+
+ public boolean smallest;
+ public String propertyName;
+ public int resultCount;
- @SuppressWarnings("unchecked")
@Override
- Collection<Resource> select(ReadGraph graph, Collection<Resource> elements) {
- List<Resource> result = new ArrayList<>(elements);
- List<Tuple2> result2 = Lists.map(new FunctionImpl1<Resource, Tuple2>() {
- @Override
- public Tuple2 apply(Resource r) {
- return new Tuple2(r, getPropertyValue(graph, r, propertyName));
- }
- }, result);
+ SelectionResult select(ReadGraph graph, Collection<Resource> elements) {
+ elements = filterElements(graph, elements);
- result2 = Lists.filter(new FunctionImpl1<Tuple2, Boolean>() {
- @Override
- public Boolean apply(Tuple2 t) {
- return t.c1 != null;
- }
- }, result2);
+ // Select sorting direction
+ Comparator<Pair<Resource, Double>> comparator = smallest ?
+ (p1, p2) -> Double.compare(p1.second, p2.second) :
+ (p1, p2) -> Double.compare(p2.second, p1.second);
- result2.sort((t1, t2) -> smallest ? Double.compare((Double) t1.c1, (Double) t2.c1) : Double.compare((Double) t2.c1, (Double) t1.c1));
+ // Get association list to property values
+ List<Pair<Resource, Double>> result2 = elements.stream()
+ .map(r -> Pair.make(r, getPropertyValue(graph, r, propertyName)))
+ .filter(t -> t.second != null)
+ .sorted(comparator)
+ .collect(Collectors.toList());
+ int count = Math.min(resultCount, result2.size());
- if (resultCount < result2.size())
- result2 = result2.subList(0, resultCount);
+ // Count number of equal values at the end of the list
+ int tailCount = 0;
+ double tailValue = count > 0 ? result2.get(count-1).second : 0.0;
+ for (int i = count-1; i >= 0; i--) {
+ if (result2.get(i).second == tailValue)
+ tailCount++;
+ else
+ break;
+ }
- result = Lists.map(new FunctionImpl1<Tuple2, Resource>() {
- @Override
- public Resource apply(Tuple2 p0) {
- return (Resource) p0.c0;
- }
- }, result2);
+ // Count number of elements with value equal to the end of the list
+ int tailSize = tailCount;
+ for (int i = count; i < result2.size(); i++) {
+ if (result2.get(i).second == tailValue)
+ tailSize++;
+ else
+ break;
+ }
- return result;
+ // Take first n items
+ if (count < result2.size()) {
+ result2 = result2.subList(0, resultCount);
+ }
+
+ // Map to list or resources
+ List<Resource> selection = result2.stream().map(p -> p.first).collect(Collectors.toList());
+ return new SelectionResult(selection, tailCount, tailSize);
}
}
// Conditions
- static abstract class Condition {
- boolean isInverse;
- abstract boolean match(ReadGraph graph, Resource r) throws DatabaseException;
+ public static abstract class Condition {
+ public Resource resource;
+ public boolean isInverse;
+
+ Condition(Resource r) {
+ resource = r;
+ isInverse = false;
+ }
+
+ Condition(ReadGraph graph, Resource r) throws DatabaseException {
+ this(r);
+ ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
+ isInverse = graph.hasStatement(r, ES.Condition_IsInverse, r);
+ }
+
+ public abstract boolean match(ReadGraph graph, Resource r) throws DatabaseException;
+ public Resource update(WriteGraph graph) throws DatabaseException {
+ ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
+
+ assert(resource != null);
+ if (isInverse)
+ graph.claim(resource, ES.Condition_IsInverse, resource);
+ else
+ graph.deny(resource, ES.Condition_IsInverse, resource);
+ return resource;
+ }
}
- static class PropertyCondition extends Condition {
- public PropertyCondition(String propertyName, Double lowerLimit, Double upperLimit) {
- super();
+ public static class PropertyCondition extends Condition {
+ public PropertyCondition(ReadGraph graph, Resource r) throws DatabaseException {
+ super(graph, r);
+
+ ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
+ this.propertyName = graph.getRelatedValue(resource, ES.PropertyCondition_HasPropertyName);
+ this.lowerLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasLowerLimit);
+ this.upperLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasUpperLimit);
+ }
+
+ public PropertyCondition(Resource r, String propertyName, Double lowerLimit, Double upperLimit) {
+ super(r);
+
this.propertyName = propertyName;
this.lowerLimit = lowerLimit;
this.upperLimit = upperLimit;
}
- String propertyName;
- Double lowerLimit;
- Double upperLimit;
+ public String propertyName;
+ public Double lowerLimit;
+ public Double upperLimit;
@Override
- boolean match(ReadGraph graph, Resource r) {
+ public boolean match(ReadGraph graph, Resource r) {
Double value = getPropertyValue(graph, r, propertyName);
- return value != null && (lowerLimit == null || value >= lowerLimit) && (upperLimit == null || value <= upperLimit);
+ boolean result = value != null && (lowerLimit == null || value >= lowerLimit) && (upperLimit == null || value <= upperLimit);
+ return result ^ isInverse;
+ }
+
+ @Override
+ public Resource update(WriteGraph graph) throws DatabaseException {
+ ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
+ Layer0 L0 = Layer0.getInstance(graph);
+
+ if (resource == null) {
+ resource = graph.newResource();
+ graph.claim(resource, L0.InstanceOf, ES.PropertyCondition);
+ }
+
+ super.update(graph);
+
+ graph.claimLiteral(resource, ES.PropertyCondition_HasPropertyName, propertyName);
+ if (lowerLimit != null)
+ graph.claimLiteral(resource, ES.PropertyCondition_HasLowerLimit, L0.Double, lowerLimit);
+ else
+ graph.deny(resource, ES.PropertyCondition_HasLowerLimit);
+
+ if (upperLimit != null)
+ graph.claimLiteral(resource, ES.PropertyCondition_HasUpperLimit, L0.Double, upperLimit);
+ else
+ graph.deny(resource, ES.PropertyCondition_HasUpperLimit);
+ return resource;
}
}
- static class RegionCondition extends Condition {
- public RegionCondition(double[] region) {
- super();
+ public static class RegionCondition extends Condition {
+ public RegionCondition(Resource r, Resource regionResource, double[] region) {
+ super(r);
this.region = region;
+ this.path = createPathForRegion(region);
+ this.regionResource = regionResource;
+ }
+
+ public RegionCondition(ReadGraph graph, Resource r) throws DatabaseException {
+ super(graph, r);
+ ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
+ DiagramRegionsResource DR = DiagramRegionsResource.getInstance(graph);
+ this.regionResource = graph.getPossibleObject(resource, ES.RegionCondition_HasRegion);
+ this.region = regionResource != null ? graph.getRelatedValue(regionResource, DR.Region_area) : null;
+ this.path = createPathForRegion(region);
+ }
+
+ public static Path2D createPathForRegion(double[] region) {
Path2D path = new Path2D.Double();
- double startX = region[0];
- double startY = region[1];
- path.moveTo(startX, startY);
- for (int i = 2; i < region.length; i+=2)
- path.lineTo(region[i], region[i+1]);
- path.closePath();
+ if (region != null) {
+ double startX = region[0];
+ double startY = region[1];
+ path.moveTo(startX, startY);
+ for (int i = 2; i < region.length; i+=2)
+ path.lineTo(region[i], region[i+1]);
+ path.closePath();
+ }
- this.path = path;
+ return path;
}
+ public Resource regionResource;
double[] region;
Path2D path;
@Override
- boolean match(ReadGraph graph, Resource r) throws DatabaseException {
+ public boolean match(ReadGraph graph, Resource r) throws DatabaseException {
double[] transform = graph.getRelatedValue(r, DIA.HasTransform);
double x = transform[4];
double y = transform[5];
- return path.contains(x, y);
- }
+ return path.contains(x, y) ^ isInverse;
+ }
+
+ @Override
+ public Resource update(WriteGraph graph) throws DatabaseException {
+ Layer0 L0 = Layer0.getInstance(graph);
+ ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
+ DiagramRegionsResource DR = DiagramRegionsResource.getInstance(graph);
+
+ if (resource == null) {
+ resource = graph.newResource();
+ graph.claim(resource, L0.InstanceOf, ES.RegionCondition);
+ }
+
+ super.update(graph);
+
+ graph.claim(resource, ES.RegionCondition_HasRegion, regionResource);
+
+ // Re-read region data to match DB
+ this.region = regionResource != null ? graph.getRelatedValue(regionResource, DR.Region_area, Bindings.DOUBLE_ARRAY) : null;
+ this.path = createPathForRegion(region);
+
+ return resource;
+ }
}
- static class RouteCondition extends Condition {
- public RouteCondition(Set<Resource> routePoints) {
- super();
+ public static class RouteCondition extends Condition {
+ public RouteCondition(Resource r, Resource routeResource, Set<Resource> routePoints) {
+ super(r);
this.routePoints = routePoints;
+ this.routeResource = routeResource;
}
- Set<Resource> routePoints;
-
- @Override
- boolean match(ReadGraph graph, Resource r) throws DatabaseException {
- return routePoints.contains(r);
+ public RouteCondition(ReadGraph graph, Resource r) throws DatabaseException {
+ super(graph, r);
+ this.routeResource = graph.getPossibleObject(resource, ES.RouteCondition_HasRoute);
+ this.routePoints = getRoutePoints(graph, routeResource);
}
- }
-
- static class DiagramCondition extends Condition {
- public DiagramCondition(Resource diagram) {
- super();
- this.diagram = diagram;
+
+ public static Set<Resource> getRoutePoints(ReadGraph graph, Resource routeResource) throws DatabaseException {
+ return routeResource != null ?
+ new HashSet<>(ListUtils.toList(graph, routeResource)) :
+ Collections.emptySet();
}
- Resource diagram;
+ public Resource routeResource;
+ Set<Resource> routePoints;
@Override
- boolean match(ReadGraph graph, Resource r) throws DatabaseException {
- return graph.getSingleObject(r, L0.PartOf).equals(diagram);
+ public boolean match(ReadGraph graph, Resource r) throws DatabaseException {
+ return routePoints.contains(r) ^ isInverse;
+ }
+
+ @Override
+ public Resource update(WriteGraph graph) throws DatabaseException {
+ ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
+ Layer0 L0 = Layer0.getInstance(graph);
+
+ if (resource == null) {
+ resource = graph.newResource();
+ graph.claim(resource, L0.InstanceOf, ES.RouteCondition);
+ }
+
+ super.update(graph);
+
+ if (routeResource != null)
+ graph.claim(resource, ES.RouteCondition_HasRoute, routeResource);
+
+ this.routePoints = getRoutePoints(graph, routeResource);
+
+ return resource;
}
}
- static class AggregateCondition extends Condition {
- static enum Type { DISJUNCTION, CONJUNCTION, NEGATION };
+ public static class AggregateCondition extends Condition {
+ public static enum Type { DISJUNCTION, CONJUNCTION, NEGATION };
- public AggregateCondition(Type type, List<Condition> conditions) {
- super();
+ public AggregateCondition(Resource r, Type type, List<Condition> conditions) {
+ super(r);
this.type = type;
this.conditions = conditions;
}
- Type type;
- List<Condition> conditions;
+ public AggregateCondition(ReadGraph graph, Resource r) throws DatabaseException {
+ super(graph, r);
+ Collection<Resource> conditionResources = graph.getObjects(resource, ES.HasSubcondition);
+ conditions = new ArrayList<>(conditionResources.size());
+ for (Resource c : conditionResources) {
+ conditions.add(buildCondition(graph, c));
+ }
+ if (graph.isInstanceOf(resource, ES.Conjunction))
+ this.type = AggregateCondition.Type.CONJUNCTION;
+ else if (graph.isInstanceOf(resource, ES.Negation))
+ this.type = AggregateCondition.Type.NEGATION;
+ else if (graph.isInstanceOf(resource, ES.Disjunction))
+ this.type = AggregateCondition.Type.DISJUNCTION;
+ else
+ throw new IllegalArgumentException("Unknown aggreate condition type " + graph.getURI(graph.getSingleType(resource)));
+ }
+
+ public Type type;
+ public List<Condition> conditions;
@Override
- boolean match(ReadGraph graph, Resource r) throws DatabaseException {
+ public boolean match(ReadGraph graph, Resource r) throws DatabaseException {
+ return doMatch(graph, r) ^ isInverse;
+ }
+
+ private boolean doMatch(ReadGraph graph, Resource r) throws DatabaseException {
switch (type) {
case DISJUNCTION:
for (Condition c : conditions)
throw new IllegalArgumentException("Unknown aggregate condition type " + type);
}
}
+
+ @Override
+ public Resource update(WriteGraph graph) throws DatabaseException {
+ Layer0 L0 = Layer0.getInstance(graph);
+ ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
+
+ if (resource == null) {
+ resource = graph.newResource();
+ } else {
+ graph.deny(resource, L0.InstanceOf);
+ graph.deny(resource, ES.HasSubcondition);
+ }
+
+ Resource type;
+ switch (this.type) {
+ case CONJUNCTION:
+ type = ES.Conjunction; break;
+ case DISJUNCTION:
+ type = ES.Disjunction; break;
+ case NEGATION:
+ type = ES.Negation; break;
+ default:
+ throw new IllegalStateException("Unknown condition type " + this.type);
+ }
+
+ graph.claim(resource, L0.InstanceOf, type);
+
+ super.update(graph);
+
+ for (Condition c : conditions) {
+ graph.claim(resource, ES.HasSubcondition, c.update(graph));
+ }
+
+ return resource;
+ }
}
public static class ElementSelectorQuery extends ResourceRead<ElementSelector> {
return new ElementSelector(graph, resource);
}
}
+
+ public final static class SelectionExpressionRequest extends ResourceRead<String> {
+ public SelectionExpressionRequest(Resource condition) {
+ super(condition);
+ }
+
+ @Override
+ public String perform(ReadGraph graph) throws DatabaseException {
+ return ElementSelector.buildExpression(graph, resource);
+ }
+ }
+
+ public static final class SelectionConditionRequest extends ResourceRead<Condition> {
+ public SelectionConditionRequest(Resource resource) {
+ super(resource);
+ }
+
+ @Override
+ public Condition perform(ReadGraph graph) throws DatabaseException {
+ return buildCondition(graph, resource);
+ }
+ }
}