1 package org.simantics.district.selection;
3 import java.awt.geom.Path2D;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.Comparator;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.List;
13 import java.util.stream.Collectors;
15 import org.simantics.Simantics;
16 import org.simantics.databoard.Bindings;
17 import org.simantics.db.ReadGraph;
18 import org.simantics.db.RequestProcessor;
19 import org.simantics.db.Resource;
20 import org.simantics.db.WriteGraph;
21 import org.simantics.db.common.request.ResourceRead;
22 import org.simantics.db.common.utils.ListUtils;
23 import org.simantics.db.exception.AssumptionException;
24 import org.simantics.db.exception.DatabaseException;
25 import org.simantics.db.exception.DoesNotContainValueException;
26 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
27 import org.simantics.db.exception.NoSingleResultException;
28 import org.simantics.db.exception.ServiceException;
29 import org.simantics.db.exception.ValidationException;
30 import org.simantics.db.layer0.QueryIndexUtils;
31 import org.simantics.db.layer0.request.ActiveModels;
32 import org.simantics.db.layer0.request.ActiveRuns;
33 import org.simantics.db.layer0.request.Configuration;
34 import org.simantics.db.layer0.request.PossibleActiveModel;
35 import org.simantics.db.layer0.variable.RVI;
36 import org.simantics.db.layer0.variable.Variable;
37 import org.simantics.db.layer0.variable.Variables;
38 import org.simantics.db.request.Read;
39 import org.simantics.diagram.stubs.DiagramResource;
40 import org.simantics.district.network.ontology.DistrictNetworkResource;
41 import org.simantics.district.region.ontology.DiagramRegionsResource;
42 import org.simantics.layer0.Layer0;
43 import org.simantics.modeling.ModelingResources;
44 import org.simantics.structural.stubs.StructuralResource2;
45 import org.simantics.utils.datastructures.Pair;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
49 public class ElementSelector {
59 static Logger LOG = LoggerFactory.getLogger(ElementSelector.class);
61 static ElementSelectionResource ES;
63 static StructuralResource2 STR;
64 static ModelingResources MOD;
65 static DiagramResource DIA;
66 static DistrictNetworkResource DN;
68 private static Logger LOGGER = LoggerFactory.getLogger(ElementSelector.class);
70 ElementSelector(ReadGraph graph, Resource resource) throws DatabaseException {
73 L0 = Layer0.getInstance(graph);
74 ES = ElementSelectionResource.getInstance(graph);
75 STR = StructuralResource2.getInstance(graph);
76 MOD = ModelingResources.getInstance(graph);
77 DIA = DiagramResource.getInstance(graph);
78 DN = DistrictNetworkResource.getInstance(graph);
80 this.resource = resource;
82 this.name = graph.getRelatedValue(resource, L0.HasLabel);
83 this.expression = getExpression(graph, resource);
84 } catch (DatabaseException e) {
85 LOG.error("Error reading element selector", e);
91 * Instantiate an element selector object for an ES.Selection resource.
93 public static ElementSelector getSelector(RequestProcessor graph, Resource resource) throws DatabaseException {
94 return graph.syncRequest(new ElementSelectorQuery(resource));
98 * Get an SQL-like textual description of an ES.Selection resource.
100 public static String getExpression(RequestProcessor graph, Resource resource) throws DatabaseException {
101 return graph.syncRequest(new SelectionExpressionRequest(resource));
105 * Get a Java object representation of an ES.Condition resource.
107 public static Condition getCondition(RequestProcessor graph, Resource condition) throws DatabaseException {
108 return graph.syncRequest(new SelectionConditionRequest(condition));
112 * Get the name of the element selector.
114 public String getName() {
119 * Get a textual SQL-like description of the element selector.
121 public String getExpression() {
126 * Get the resource that this selector represents.
128 public Resource getResource() {
133 * Get the generator component. Use {@link #buildSelection(ReadGraph)} to make it available first.
135 public Generator getGenerator() {
140 * Get the selector component. Use {@link #buildSelection(ReadGraph)} to make it available first.
142 public Selector getSelector() {
147 * Get the condition component. Use {@link #buildSelection(ReadGraph)} to make it available first.
149 public Condition getCondition() {
156 * @throws DatabaseException
158 public void buildSelection(ReadGraph graph) throws DatabaseException {
159 Resource selector = graph.getSingleObject(resource, ES.Selection_HasSelector);
160 Resource generator = graph.getSingleObject(resource, ES.Selection_HasGenerator);
161 Resource condition = graph.getPossibleObject(resource, ES.Selection_HasCondition);
163 this.selector = buildSelector(graph, selector);
164 this.generator = buildGenerator(graph, generator);
165 this.condition = buildCondition(graph, condition);
168 public static Map<Resource, String> findDiagrams() {
170 return Simantics.getSession().syncRequest(new Read<Map<Resource, String>>() {
172 public Map<Resource, String> perform(ReadGraph graph) throws DatabaseException {
173 Layer0 L0 = Layer0.getInstance(graph);
174 StructuralResource2 STR = StructuralResource2.getInstance(graph);
175 DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
176 ModelingResources MOD = ModelingResources.getInstance(graph);
178 Map<Resource, String> result = new HashMap<>();
179 Resource model = graph.syncRequest(new PossibleActiveModel(Simantics.getProjectResource()));
180 List<Resource> composites = QueryIndexUtils.searchByType(graph, model, STR.Composite);
181 for (Resource r : composites) {
183 Resource diagram = graph.getPossibleObject(r, MOD.CompositeToDiagram);
184 if (diagram == null || !graph.isInstanceOf(diagram, DN.Diagram))
187 // Filter out user component diagrams
188 Resource parent = graph.getPossibleObject(r, L0.PartOf);
189 if (parent == null || graph.isInheritedFrom(parent, STR.Component))
192 result.put(r, graph.getRelatedValue(r, L0.HasName));
198 } catch (DatabaseException e) {
199 LOGGER.error("Query for model diagrams failed", e);
200 return Collections.emptyMap();
204 public static Variable getVariableForElement(ReadGraph graph, Resource element) throws DatabaseException {
205 Resource component = graph.getPossibleObject(element, MOD.ElementToComponent);
206 if (component != null) {
207 Variable var = Variables.getVariable(graph, component);
208 RVI realRvi = var.getRVI(graph);
210 for (Resource activeModel : graph.syncRequest(new ActiveModels(Simantics.getProjectResource()))) {
211 for (Variable run : graph.syncRequest(new ActiveRuns(activeModel))) {
212 Variable v = realRvi.resolvePossible(graph, run);
217 Variable configuration = Variables.getPossibleConfigurationContext(graph, activeModel);
218 if (configuration != null) {
219 Variable v = realRvi.resolvePossible(graph, configuration);
230 public static Double getPropertyValue(ReadGraph graph, Resource element, String propertyName) {
232 Variable v = getVariableForElement(graph, element);
234 Number value = v.getPossiblePropertyValue(graph, propertyName);
236 return value.doubleValue();
239 // No property found - try possible mapped element property as well
240 Resource mappedElement = graph.getPossibleObject(element, DN.MappedComponent);
241 if (mappedElement != null)
242 return getPropertyValue(graph, mappedElement, propertyName);
244 catch (DatabaseException e) {
250 public SelectionResult selectElementsFrom(ReadGraph graph, Resource model) throws DatabaseException {
251 if (selector == null) {
252 buildSelection(graph);
255 return gather(graph, model);
258 private static Generator buildGenerator(ReadGraph graph, Resource resource) throws DatabaseException {
259 if (!graph.isInstanceOf(resource, ES.Generator))
260 throw new IllegalArgumentException("Resource " + resource + " is not a valid generator");
262 if (graph.isInstanceOf(resource, ES.Generator_Model))
263 return new ModelGenerator();
264 else if (graph.isInstanceOf(resource, ES.Generator_Diagram))
265 return new DiagramGenerator(graph.getSingleObject(resource, ES.Generator_HasDiagram));
266 else if (graph.isInstanceOf(resource, ES.Generator_Explicit))
267 return new ExplicitGenerator(graph.getObjects(resource, ES.Generator_HasSelectedElement));
269 throw new IllegalArgumentException("Unknown generator type " + graph.getURI(graph.getSingleType(resource)));
272 private static Selector buildSelector(ReadGraph graph, Resource resource) throws DatabaseException {
273 if (!graph.isInstanceOf(resource, ES.Selector))
274 throw new IllegalArgumentException("Resource " + resource + " is not a valid selector");
277 if (graph.isInstanceOf(resource, ES.Selector_All))
279 else if (graph.isInstanceOf(resource, ES.PropertySelector))
280 s = new PropertySelector(graph, resource);
282 throw new IllegalArgumentException("Unknown selector type " + graph.getURI(graph.getSingleType(resource)));
284 Resource mapping = graph.getPossibleObject(resource, ES.Selector_HasMapping);
285 s.componentType = mapping;
290 private static Condition buildCondition(ReadGraph graph, Resource resource) throws DatabaseException {
291 if (resource == null)
294 if (!graph.isInstanceOf(resource, ES.Condition))
295 throw new IllegalArgumentException("Resource " + resource + " is not a valid condition");
298 if (graph.isInstanceOf(resource, ES.PropertyCondition))
299 cond = new PropertyCondition(graph, resource);
300 else if (graph.isInstanceOf(resource, ES.RegionCondition))
301 cond = new RegionCondition(graph, resource);
302 else if (graph.isInstanceOf(resource, ES.RouteCondition))
303 cond = new RouteCondition(graph, resource);
304 else if (graph.isInstanceOf(resource, ES.AggregateCondition))
305 cond = new AggregateCondition(graph, resource);
307 throw new IllegalArgumentException("Unknown condition type " + graph.getURI(graph.getSingleType(resource)));
312 private static String buildExpression(ReadGraph graph, Resource r) throws DatabaseException {
313 if (graph.isInstanceOf(r, ES.Selection))
314 return buildSelectionExpression(graph, r);
315 else if (graph.isInstanceOf(r, ES.Condition))
316 return buildConditionExpression(graph, r);
317 else if (graph.isInstanceOf(r, ES.Selector))
318 return buildSelectorExpression(graph, r);
319 else if (graph.isInstanceOf(r, ES.Generator))
320 return buildGeneratorExpression(graph, r);
322 throw new DatabaseException("Unsupported resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
325 private static String buildSelectionExpression(ReadGraph graph, Resource r) throws DatabaseException,
326 NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException {
327 String exp = "select " + getExpression(graph, graph.getSingleObject(r, ES.Selection_HasSelector)) +
328 " from " + getExpression(graph, graph.getSingleObject(r, ES.Selection_HasGenerator));
330 Resource cond = graph.getPossibleObject(r, ES.Selection_HasCondition);
331 return cond != null ? exp + " where {" + getExpression(graph, cond) + "}" : exp;
334 private static String buildGeneratorExpression(ReadGraph graph, Resource r)
335 throws ServiceException, NoSingleResultException, DoesNotContainValueException,
336 ManyObjectsForFunctionalRelationException, DatabaseException, AssumptionException, ValidationException {
337 if (graph.isInstanceOf(r, ES.Generator_Model)) {
340 else if (graph.isInstanceOf(r, ES.Generator_Diagram)) {
341 return "diagram \"" + graph.getRelatedValue(graph.getSingleObject(r, ES.Generator_HasDiagram), L0.HasName) + "\"";
343 else if (graph.isInstanceOf(r, ES.Generator_Explicit)) {
344 return "<list of " + graph.getObjects(r, ES.Generator_HasSelectedElement).size() + " elements>";
347 throw new DatabaseException("Unsupported generator resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
351 private static String buildSelectorExpression(ReadGraph graph, Resource r)
352 throws ServiceException, NoSingleResultException, DoesNotContainValueException, DatabaseException,
353 AssumptionException, ValidationException, ManyObjectsForFunctionalRelationException {
355 if (graph.isInstanceOf(r, ES.Selector_All)) {
358 else if (graph.isInstanceOf(r, ES.PropertySelector)) {
359 Integer count = graph.getRelatedValue(r, ES.PropertySelector_HasResultCount);
360 exp = count.toString();
363 throw new DatabaseException("Unsupported selector resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
366 Resource mapping = graph.getPossibleObject(r, ES.Selector_HasMapping);
367 if (mapping != null) {
368 String name = graph.getRelatedValue2(mapping, L0.HasName);
369 exp = exp + " " + name;
371 exp = exp + " elements";
374 if (graph.isInstanceOf(r, ES.PropertySelector)) {
376 if (graph.isInstanceOf(r, ES.Selector_NLowest))
378 else if (graph.isInstanceOf(r, ES.Selector_NHighest))
381 throw new DatabaseException("Unsupported property selector resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
383 String name = graph.getRelatedValue(r, ES.PropertySelector_HasSelectionPropertyName);
384 exp = exp + " with " + op + " " + name;
390 private static String buildConditionExpression(ReadGraph graph, Resource r) throws ServiceException,
391 DatabaseException, NoSingleResultException, ManyObjectsForFunctionalRelationException,
392 DoesNotContainValueException, AssumptionException, ValidationException {
394 boolean isInverse = graph.hasStatement(r, ES.Condition_IsInverse, r);
395 if (graph.isInstanceOf(r, ES.PropertyCondition)) {
396 result = buildPropertyConditionExpression(graph, r);
398 else if (graph.isInstanceOf(r, ES.RegionCondition)) {
399 result = buildRegionConditionExpression(graph, r);
401 else if (graph.isInstanceOf(r, ES.RouteCondition)) {
402 result = buildRouteConditionExpression(graph, r);
404 else if (graph.isInstanceOf(r, ES.AggregateCondition)) {
405 // This handles isInverse internally
406 return buildAggregateConditionExpression(graph, r, isInverse);
409 throw new DatabaseException("Unsupported condition resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
413 result = "not {" + result + "}";
418 private static String buildAggregateConditionExpression(ReadGraph graph, Resource r, boolean isInverse)
419 throws ServiceException, DatabaseException {
421 String op = graph.isInstanceOf(r, ES.Conjunction) ? " and " : " or ";
422 List<String> exps = new ArrayList<>();
423 Collection<Resource> objects = graph.getObjects(r, ES.HasSubcondition);
424 for (Resource c : objects) {
425 String exp = getExpression(graph, c);
426 exps.add(objects.size() > 1 ? "{" + exp + "}" : exp);
428 result = String.join(op, exps);
429 if (graph.isInstanceOf(r, ES.Negation) ^ isInverse)
430 result = "not {" + result + "}";
434 private static String buildRouteConditionExpression(ReadGraph graph, Resource r) throws NoSingleResultException,
435 ManyObjectsForFunctionalRelationException, ServiceException, DoesNotContainValueException {
437 Resource route = graph.getSingleObject(r, ES.RouteCondition_HasRoute);
438 String name = graph.getRelatedValue(route, L0.HasLabel);
439 result = "in route " + name;
443 private static String buildRegionConditionExpression(ReadGraph graph, Resource r) throws NoSingleResultException,
444 ManyObjectsForFunctionalRelationException, ServiceException, DoesNotContainValueException {
446 Resource region = graph.getSingleObject(r, ES.RegionCondition_HasRegion);
447 String name = graph.getRelatedValue(region, L0.HasLabel);
448 result = "in region " + name;
452 private static String buildPropertyConditionExpression(ReadGraph graph, Resource r) throws DatabaseException {
453 String propertyName = graph.getRelatedValue(r, ES.PropertyCondition_HasPropertyName);
454 Double lowerLimit = graph.getPossibleRelatedValue(r, ES.PropertyCondition_HasLowerLimit);
455 Double upperLimit = graph.getPossibleRelatedValue(r, ES.PropertyCondition_HasUpperLimit);
456 if (upperLimit == null) {
457 if (lowerLimit == null) {
458 return "has property " + propertyName;
460 return propertyName + " \u2265 " + lowerLimit;
463 StringBuilder result = new StringBuilder();
464 if (lowerLimit != null) {
465 result.append(lowerLimit);
466 result.append(" \u2264 ");
468 result.append(propertyName);
469 result.append(" \u2264 ");
470 result.append(upperLimit);
471 return result.toString();
475 private static Collection<Resource> elementsOfDiagram(ReadGraph graph, Resource diagram) throws DatabaseException {
476 if (graph.isInstanceOf(diagram, STR.Composite)) {
477 // Resource is a composite - get diagram
478 return elementsOfDiagram(graph, graph.getSingleObject(diagram, MOD.CompositeToDiagram));
481 Collection<Resource> elements = graph.getObjects(diagram, L0.ConsistsOf);
482 Collection<Resource> result = new ArrayList<>();
483 for (Resource r : elements)
484 if (graph.isInstanceOf(r, DIA.Element))
489 private Collection<Resource> filterElementsFrom(ReadGraph graph, Collection<Resource> elements) throws DatabaseException {
490 if (condition == null) return elements;
492 ArrayList<Resource> result = new ArrayList<>();
493 for (Resource r : elements) {
494 if (condition.match(graph, r))
501 private SelectionResult gather(ReadGraph graph, Resource model) throws DatabaseException {
502 return selector.select(graph, filterElementsFrom(graph, generator.generate(graph, model)));
507 public static abstract class Generator {
508 abstract Collection<Resource> generate(ReadGraph graph, Resource model) throws DatabaseException;
511 public static class ModelGenerator extends Generator {
513 Collection<Resource> generate(ReadGraph graph, Resource model) throws DatabaseException {
514 Resource conf = graph.syncRequest(new Configuration(model));
516 HashMap<Resource, Resource> fromMapped = new HashMap<Resource, Resource>();
518 // Iterate over diagrams
519 // Each model element is represented by the corresponding mapping element, if present
520 for (Resource comp : graph.getObjects(conf, L0.ConsistsOf)) {
521 if (!graph.isInstanceOf(comp, STR.Composite)) continue;
523 Resource diagram = graph.getPossibleObject(comp, MOD.CompositeToDiagram);
524 if (diagram != null) {
525 for (Resource elem : elementsOfDiagram(graph, diagram)) {
526 Resource mapped = graph.getPossibleObject(elem, DN.MappedComponent);
527 if (mapped != null) {
528 fromMapped.put(mapped, elem);
530 else if (!fromMapped.containsKey(elem)) {
531 fromMapped.put(elem, elem);
537 return new ArrayList<>(fromMapped.values());
541 public static class DiagramGenerator extends Generator {
542 public Resource diagram;
544 public DiagramGenerator(Resource diagram) {
545 this.diagram = diagram;
549 Collection<Resource> generate(ReadGraph graph, Resource model) throws DatabaseException {
550 return elementsOfDiagram(graph, diagram);
554 public static class ExplicitGenerator extends Generator {
555 public ExplicitGenerator(Collection<Resource> elements) {
556 this.elements = elements;
559 public Collection<Resource> elements;
562 Collection<Resource> generate(ReadGraph graph, Resource model) {
569 public static class SelectionResult {
570 public final Collection<Resource> elements;
571 public final int tailCount;
572 public final int tailSize;
574 public SelectionResult(Collection<Resource> elements, int tailCount, int tailSize) {
575 this.elements = elements;
576 this.tailCount = tailCount;
577 this.tailSize = tailSize;
581 public static abstract class Selector {
582 public Resource componentType = null;
584 abstract SelectionResult select(ReadGraph graph, Collection<Resource> elements);
586 Collection<Resource> filterElements(ReadGraph graph, Collection<Resource> elements) {
587 if (componentType == null)
590 Collection<Resource> selected = new HashSet<>(elements.size());
591 for (Resource r : elements) {
593 if (graph.hasStatement(r, DN.HasMapping, componentType))
595 } catch (DatabaseException e) {
596 // Just leave it out of the result
604 public static class All extends Selector {
609 SelectionResult select(ReadGraph graph, Collection<Resource> elements) {
610 Collection<Resource> selected = filterElements(graph, elements);
611 return new SelectionResult(selected, 0, 0);
615 public static class PropertySelector extends Selector {
616 public PropertySelector(boolean smallest, String propertyName, int resultCount) {
617 this.smallest = smallest;
618 this.propertyName = propertyName;
619 this.resultCount = resultCount;
622 public PropertySelector(ReadGraph graph, Resource resource) throws DatabaseException {
623 this.propertyName = graph.getRelatedValue(resource, ES.PropertySelector_HasSelectionPropertyName);
624 this.resultCount = graph.getRelatedValue(resource, ES.PropertySelector_HasResultCount);
625 this.smallest = graph.isInstanceOf(resource, ES.Selector_NLowest);
628 public boolean smallest;
629 public String propertyName;
630 public int resultCount;
633 SelectionResult select(ReadGraph graph, Collection<Resource> elements) {
634 elements = filterElements(graph, elements);
636 // Select sorting direction
637 Comparator<Pair<Resource, Double>> comparator = smallest ?
638 (p1, p2) -> Double.compare(p1.second, p2.second) :
639 (p1, p2) -> Double.compare(p1.second, p2.second);
641 // Get association list to property values
642 List<Pair<Resource, Double>> result2 = elements.stream()
643 .map(r -> Pair.make(r, getPropertyValue(graph, r, propertyName)))
644 .filter(t -> t.second != null)
646 .collect(Collectors.toList());
647 int count = Math.min(resultCount, result2.size());
649 // Count number of equal values at the end of the list
651 double tailValue = count > 0 ? result2.get(count-1).second : 0.0;
652 for (int i = count-1; i >= 0; i--) {
653 if (result2.get(i).second == tailValue)
659 // Count number of elements with value equal to the end of the list
660 int tailSize = tailCount;
661 for (int i = count; i < result2.size(); i++) {
662 if (result2.get(i).second == tailValue)
668 // Take first n items
669 if (count < result2.size()) {
670 result2 = result2.subList(0, resultCount);
673 // Map to list or resources
674 List<Resource> selection = result2.stream().map(p -> p.first).collect(Collectors.toList());
675 return new SelectionResult(selection, tailCount, tailSize);
681 public static abstract class Condition {
682 public Resource resource;
683 public boolean isInverse;
685 Condition(Resource r) {
690 Condition(ReadGraph graph, Resource r) throws DatabaseException {
692 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
693 isInverse = graph.hasStatement(r, ES.Condition_IsInverse, r);
696 public abstract boolean match(ReadGraph graph, Resource r) throws DatabaseException;
697 public Resource update(WriteGraph graph) throws DatabaseException {
698 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
700 assert(resource != null);
702 graph.claim(resource, ES.Condition_IsInverse, resource);
704 graph.deny(resource, ES.Condition_IsInverse, resource);
709 public static class PropertyCondition extends Condition {
710 public PropertyCondition(ReadGraph graph, Resource r) throws DatabaseException {
713 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
714 this.propertyName = graph.getRelatedValue(resource, ES.PropertyCondition_HasPropertyName);
715 this.lowerLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasLowerLimit);
716 this.upperLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasUpperLimit);
719 public PropertyCondition(Resource r, String propertyName, Double lowerLimit, Double upperLimit) {
722 this.propertyName = propertyName;
723 this.lowerLimit = lowerLimit;
724 this.upperLimit = upperLimit;
727 public String propertyName;
728 public Double lowerLimit;
729 public Double upperLimit;
732 public boolean match(ReadGraph graph, Resource r) {
733 Double value = getPropertyValue(graph, r, propertyName);
734 boolean result = value != null && (lowerLimit == null || value >= lowerLimit) && (upperLimit == null || value <= upperLimit);
735 return result ^ isInverse;
739 public Resource update(WriteGraph graph) throws DatabaseException {
740 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
741 Layer0 L0 = Layer0.getInstance(graph);
743 if (resource == null) {
744 resource = graph.newResource();
745 graph.claim(resource, L0.InstanceOf, ES.PropertyCondition);
750 graph.claimLiteral(resource, ES.PropertyCondition_HasPropertyName, propertyName);
751 if (lowerLimit != null)
752 graph.claimLiteral(resource, ES.PropertyCondition_HasLowerLimit, L0.Double, lowerLimit);
754 graph.deny(resource, ES.PropertyCondition_HasLowerLimit);
756 if (upperLimit != null)
757 graph.claimLiteral(resource, ES.PropertyCondition_HasUpperLimit, L0.Double, upperLimit);
759 graph.deny(resource, ES.PropertyCondition_HasUpperLimit);
764 public static class RegionCondition extends Condition {
765 public RegionCondition(Resource r, Resource regionResource, double[] region) {
767 this.region = region;
768 this.path = createPathForRegion(region);
769 this.regionResource = regionResource;
772 public RegionCondition(ReadGraph graph, Resource r) throws DatabaseException {
775 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
776 DiagramRegionsResource DR = DiagramRegionsResource.getInstance(graph);
777 this.regionResource = graph.getPossibleObject(resource, ES.RegionCondition_HasRegion);
778 this.region = regionResource != null ? graph.getRelatedValue(regionResource, DR.Region_area) : null;
779 this.path = createPathForRegion(region);
782 public static Path2D createPathForRegion(double[] region) {
783 Path2D path = new Path2D.Double();
784 if (region != null) {
785 double startX = region[0];
786 double startY = region[1];
787 path.moveTo(startX, startY);
788 for (int i = 2; i < region.length; i+=2)
789 path.lineTo(region[i], region[i+1]);
796 public Resource regionResource;
801 public boolean match(ReadGraph graph, Resource r) throws DatabaseException {
802 double[] transform = graph.getRelatedValue(r, DIA.HasTransform);
803 double x = transform[4];
804 double y = transform[5];
805 return path.contains(x, y) ^ isInverse;
809 public Resource update(WriteGraph graph) throws DatabaseException {
810 Layer0 L0 = Layer0.getInstance(graph);
811 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
812 DiagramRegionsResource DR = DiagramRegionsResource.getInstance(graph);
814 if (resource == null) {
815 resource = graph.newResource();
816 graph.claim(resource, L0.InstanceOf, ES.RegionCondition);
821 graph.claim(resource, ES.RegionCondition_HasRegion, regionResource);
823 // Re-read region data to match DB
824 this.region = regionResource != null ? graph.getRelatedValue(regionResource, DR.Region_area, Bindings.DOUBLE_ARRAY) : null;
825 this.path = createPathForRegion(region);
831 public static class RouteCondition extends Condition {
832 public RouteCondition(Resource r, Resource routeResource, Set<Resource> routePoints) {
834 this.routePoints = routePoints;
835 this.routeResource = routeResource;
838 public RouteCondition(ReadGraph graph, Resource r) throws DatabaseException {
840 this.routeResource = graph.getPossibleObject(resource, ES.RouteCondition_HasRoute);
841 this.routePoints = getRoutePoints(graph, routeResource);
844 public static Set<Resource> getRoutePoints(ReadGraph graph, Resource routeResource) throws DatabaseException {
845 return routeResource != null ?
846 new HashSet<>(ListUtils.toList(graph, routeResource)) :
847 Collections.emptySet();
850 public Resource routeResource;
851 Set<Resource> routePoints;
854 public boolean match(ReadGraph graph, Resource r) throws DatabaseException {
855 return routePoints.contains(r) ^ isInverse;
859 public Resource update(WriteGraph graph) throws DatabaseException {
860 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
861 Layer0 L0 = Layer0.getInstance(graph);
863 if (resource == null) {
864 resource = graph.newResource();
865 graph.claim(resource, L0.InstanceOf, ES.RouteCondition);
870 if (routeResource != null)
871 graph.claim(resource, ES.RouteCondition_HasRoute, routeResource);
873 this.routePoints = getRoutePoints(graph, routeResource);
879 public static class AggregateCondition extends Condition {
880 public static enum Type { DISJUNCTION, CONJUNCTION, NEGATION };
882 public AggregateCondition(Resource r, Type type, List<Condition> conditions) {
885 this.conditions = conditions;
888 public AggregateCondition(ReadGraph graph, Resource r) throws DatabaseException {
890 Collection<Resource> conditionResources = graph.getObjects(resource, ES.HasSubcondition);
891 conditions = new ArrayList<>(conditionResources.size());
892 for (Resource c : conditionResources) {
893 conditions.add(buildCondition(graph, c));
895 if (graph.isInstanceOf(resource, ES.Conjunction))
896 this.type = AggregateCondition.Type.CONJUNCTION;
897 else if (graph.isInstanceOf(resource, ES.Negation))
898 this.type = AggregateCondition.Type.NEGATION;
899 else if (graph.isInstanceOf(resource, ES.Disjunction))
900 this.type = AggregateCondition.Type.DISJUNCTION;
902 throw new IllegalArgumentException("Unknown aggreate condition type " + graph.getURI(graph.getSingleType(resource)));
906 public List<Condition> conditions;
909 public boolean match(ReadGraph graph, Resource r) throws DatabaseException {
910 return doMatch(graph, r) ^ isInverse;
913 private boolean doMatch(ReadGraph graph, Resource r) throws DatabaseException {
916 for (Condition c : conditions)
917 if (c.match(graph, r)) return true;
920 for (Condition c : conditions)
921 if (!c.match(graph, r)) return false;
924 for (Condition c : conditions)
925 if (c.match(graph, r)) return false;
929 throw new IllegalArgumentException("Unknown aggregate condition type " + type);
934 public Resource update(WriteGraph graph) throws DatabaseException {
935 Layer0 L0 = Layer0.getInstance(graph);
936 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
938 if (resource == null) {
939 resource = graph.newResource();
941 graph.deny(resource, L0.InstanceOf);
942 graph.deny(resource, ES.HasSubcondition);
948 type = ES.Conjunction; break;
950 type = ES.Disjunction; break;
952 type = ES.Negation; break;
954 throw new IllegalStateException("Unknown condition type " + this.type);
957 graph.claim(resource, L0.InstanceOf, type);
961 for (Condition c : conditions) {
962 graph.claim(resource, ES.HasSubcondition, c.update(graph));
969 public static class ElementSelectorQuery extends ResourceRead<ElementSelector> {
970 public ElementSelectorQuery(Resource resource) {
975 public ElementSelector perform(ReadGraph graph) throws DatabaseException {
976 return new ElementSelector(graph, resource);
980 public final static class SelectionExpressionRequest extends ResourceRead<String> {
981 public SelectionExpressionRequest(Resource condition) {
986 public String perform(ReadGraph graph) throws DatabaseException {
987 return ElementSelector.buildExpression(graph, resource);
991 public static final class SelectionConditionRequest extends ResourceRead<Condition> {
992 public SelectionConditionRequest(Resource resource) {
997 public Condition perform(ReadGraph graph) throws DatabaseException {
998 return buildCondition(graph, resource);