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 Map<Resource, String> result = new HashMap<>();
174 Resource model = graph.syncRequest(new PossibleActiveModel(Simantics.getProjectResource()));
175 List<Resource> composites = QueryIndexUtils.searchByType(graph, model, StructuralResource2.getInstance(graph).Composite);
176 for (Resource r : composites) {
178 Resource diagram = graph.getPossibleObject(r, ModelingResources.getInstance(graph).CompositeToDiagram);
179 if (diagram == null) continue;
181 // Filter out user component diagrams
182 Resource parent = graph.getPossibleObject(r, Layer0.getInstance(graph).PartOf);
183 if (parent == null || graph.isInheritedFrom(parent, StructuralResource2.getInstance(graph).Component))
186 result.put(r, graph.getRelatedValue(r, Layer0.getInstance(graph).HasName));
192 } catch (DatabaseException e) {
193 LOGGER.error("Query for model diagrams failed", e);
194 return Collections.emptyMap();
198 public static Variable getVariableForElement(ReadGraph graph, Resource element) throws DatabaseException {
199 Resource component = graph.getPossibleObject(element, MOD.ElementToComponent);
200 if (component != null) {
201 Variable var = Variables.getVariable(graph, component);
202 RVI realRvi = var.getRVI(graph);
204 for (Resource activeModel : graph.syncRequest(new ActiveModels(Simantics.getProjectResource()))) {
205 for (Variable run : graph.syncRequest(new ActiveRuns(activeModel))) {
206 Variable v = realRvi.resolvePossible(graph, run);
211 Variable configuration = Variables.getPossibleConfigurationContext(graph, activeModel);
212 if (configuration != null) {
213 Variable v = realRvi.resolvePossible(graph, configuration);
224 public static Double getPropertyValue(ReadGraph graph, Resource element, String propertyName) {
226 Variable v = getVariableForElement(graph, element);
228 Number value = v.getPossiblePropertyValue(graph, propertyName);
230 return value.doubleValue();
233 // No property found - try possible mapped element property as well
234 Resource mappedElement = graph.getPossibleObject(element, DN.MappedComponent);
235 if (mappedElement != null)
236 return getPropertyValue(graph, mappedElement, propertyName);
238 catch (DatabaseException e) {
244 public SelectionResult selectElementsFrom(ReadGraph graph, Resource model) throws DatabaseException {
245 if (selector == null) {
246 buildSelection(graph);
249 return gather(graph, model);
252 private static Generator buildGenerator(ReadGraph graph, Resource resource) throws DatabaseException {
253 if (!graph.isInstanceOf(resource, ES.Generator))
254 throw new IllegalArgumentException("Resource " + resource + " is not a valid generator");
256 if (graph.isInstanceOf(resource, ES.Generator_Model))
257 return new ModelGenerator();
258 else if (graph.isInstanceOf(resource, ES.Generator_Diagram))
259 return new DiagramGenerator(graph.getSingleObject(resource, ES.Generator_HasDiagram));
260 else if (graph.isInstanceOf(resource, ES.Generator_Explicit))
261 return new ExplicitGenerator(graph.getObjects(resource, ES.Generator_HasSelectedElement));
263 throw new IllegalArgumentException("Unknown generator type " + graph.getURI(graph.getSingleType(resource)));
266 private static Selector buildSelector(ReadGraph graph, Resource resource) throws DatabaseException {
267 if (!graph.isInstanceOf(resource, ES.Selector))
268 throw new IllegalArgumentException("Resource " + resource + " is not a valid selector");
271 if (graph.isInstanceOf(resource, ES.Selector_All))
273 else if (graph.isInstanceOf(resource, ES.PropertySelector))
274 s = new PropertySelector(graph, resource);
276 throw new IllegalArgumentException("Unknown selector type " + graph.getURI(graph.getSingleType(resource)));
278 Resource mapping = graph.getPossibleObject(resource, ES.Selector_HasMapping);
279 s.componentType = mapping;
284 private static Condition buildCondition(ReadGraph graph, Resource resource) throws DatabaseException {
285 if (resource == null)
288 if (!graph.isInstanceOf(resource, ES.Condition))
289 throw new IllegalArgumentException("Resource " + resource + " is not a valid condition");
292 if (graph.isInstanceOf(resource, ES.PropertyCondition))
293 cond = new PropertyCondition(graph, resource);
294 else if (graph.isInstanceOf(resource, ES.RegionCondition))
295 cond = new RegionCondition(graph, resource);
296 else if (graph.isInstanceOf(resource, ES.RouteCondition))
297 cond = new RouteCondition(graph, resource);
298 else if (graph.isInstanceOf(resource, ES.AggregateCondition))
299 cond = new AggregateCondition(graph, resource);
301 throw new IllegalArgumentException("Unknown condition type " + graph.getURI(graph.getSingleType(resource)));
306 private static String buildExpression(ReadGraph graph, Resource r) throws DatabaseException {
307 if (graph.isInstanceOf(r, ES.Selection))
308 return buildSelectionExpression(graph, r);
309 else if (graph.isInstanceOf(r, ES.Condition))
310 return buildConditionExpression(graph, r);
311 else if (graph.isInstanceOf(r, ES.Selector))
312 return buildSelectorExpression(graph, r);
313 else if (graph.isInstanceOf(r, ES.Generator))
314 return buildGeneratorExpression(graph, r);
316 throw new DatabaseException("Unsupported resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
319 private static String buildSelectionExpression(ReadGraph graph, Resource r) throws DatabaseException,
320 NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException {
321 String exp = "select " + getExpression(graph, graph.getSingleObject(r, ES.Selection_HasSelector)) +
322 " from " + getExpression(graph, graph.getSingleObject(r, ES.Selection_HasGenerator));
324 Resource cond = graph.getPossibleObject(r, ES.Selection_HasCondition);
325 return cond != null ? exp + " where {" + getExpression(graph, cond) + "}" : exp;
328 private static String buildGeneratorExpression(ReadGraph graph, Resource r)
329 throws ServiceException, NoSingleResultException, DoesNotContainValueException,
330 ManyObjectsForFunctionalRelationException, DatabaseException, AssumptionException, ValidationException {
331 if (graph.isInstanceOf(r, ES.Generator_Model)) {
334 else if (graph.isInstanceOf(r, ES.Generator_Diagram)) {
335 return "diagram \"" + graph.getRelatedValue(graph.getSingleObject(r, ES.Generator_HasDiagram), L0.HasName) + "\"";
337 else if (graph.isInstanceOf(r, ES.Generator_Explicit)) {
338 return "<list of " + graph.getObjects(r, ES.Generator_HasSelectedElement).size() + " elements>";
341 throw new DatabaseException("Unsupported generator resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
345 private static String buildSelectorExpression(ReadGraph graph, Resource r)
346 throws ServiceException, NoSingleResultException, DoesNotContainValueException, DatabaseException,
347 AssumptionException, ValidationException, ManyObjectsForFunctionalRelationException {
349 if (graph.isInstanceOf(r, ES.Selector_All)) {
352 else if (graph.isInstanceOf(r, ES.PropertySelector)) {
353 Integer count = graph.getRelatedValue(r, ES.PropertySelector_HasResultCount);
354 exp = count.toString();
357 throw new DatabaseException("Unsupported selector resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
360 Resource mapping = graph.getPossibleObject(r, ES.Selector_HasMapping);
361 if (mapping != null) {
362 String name = graph.getRelatedValue2(mapping, L0.HasName);
363 exp = exp + " " + name;
365 exp = exp + " elements";
368 if (graph.isInstanceOf(r, ES.PropertySelector)) {
370 if (graph.isInstanceOf(r, ES.Selector_NLowest))
372 else if (graph.isInstanceOf(r, ES.Selector_NHighest))
375 throw new DatabaseException("Unsupported property selector resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
377 String name = graph.getRelatedValue(r, ES.PropertySelector_HasSelectionPropertyName);
378 exp = exp + " with " + op + " " + name;
384 private static String buildConditionExpression(ReadGraph graph, Resource r) throws ServiceException,
385 DatabaseException, NoSingleResultException, ManyObjectsForFunctionalRelationException,
386 DoesNotContainValueException, AssumptionException, ValidationException {
388 boolean isInverse = graph.hasStatement(r, ES.Condition_IsInverse, r);
389 if (graph.isInstanceOf(r, ES.PropertyCondition)) {
390 result = buildPropertyConditionExpression(graph, r);
392 else if (graph.isInstanceOf(r, ES.RegionCondition)) {
393 result = buildRegionConditionExpression(graph, r);
395 else if (graph.isInstanceOf(r, ES.RouteCondition)) {
396 result = buildRouteConditionExpression(graph, r);
398 else if (graph.isInstanceOf(r, ES.AggregateCondition)) {
399 // This handles isInverse internally
400 return buildAggregateConditionExpression(graph, r, isInverse);
403 throw new DatabaseException("Unsupported condition resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
407 result = "not {" + result + "}";
412 private static String buildAggregateConditionExpression(ReadGraph graph, Resource r, boolean isInverse)
413 throws ServiceException, DatabaseException {
415 String op = graph.isInstanceOf(r, ES.Conjunction) ? " and " : " or ";
416 List<String> exps = new ArrayList<>();
417 Collection<Resource> objects = graph.getObjects(r, ES.HasSubcondition);
418 for (Resource c : objects) {
419 String exp = getExpression(graph, c);
420 exps.add(objects.size() > 1 ? "{" + exp + "}" : exp);
422 result = String.join(op, exps);
423 if (graph.isInstanceOf(r, ES.Negation) ^ isInverse)
424 result = "not {" + result + "}";
428 private static String buildRouteConditionExpression(ReadGraph graph, Resource r) throws NoSingleResultException,
429 ManyObjectsForFunctionalRelationException, ServiceException, DoesNotContainValueException {
431 Resource route = graph.getSingleObject(r, ES.RouteCondition_HasRoute);
432 String name = graph.getRelatedValue(route, L0.HasLabel);
433 result = "in route " + name;
437 private static String buildRegionConditionExpression(ReadGraph graph, Resource r) throws NoSingleResultException,
438 ManyObjectsForFunctionalRelationException, ServiceException, DoesNotContainValueException {
440 Resource region = graph.getSingleObject(r, ES.RegionCondition_HasRegion);
441 String name = graph.getRelatedValue(region, L0.HasLabel);
442 result = "in region " + name;
446 private static String buildPropertyConditionExpression(ReadGraph graph, Resource r) throws DatabaseException {
447 String propertyName = graph.getRelatedValue(r, ES.PropertyCondition_HasPropertyName);
448 Double lowerLimit = graph.getPossibleRelatedValue(r, ES.PropertyCondition_HasLowerLimit);
449 Double upperLimit = graph.getPossibleRelatedValue(r, ES.PropertyCondition_HasUpperLimit);
450 if (upperLimit == null) {
451 if (lowerLimit == null) {
452 return "has property " + propertyName;
454 return propertyName + " \u2265 " + lowerLimit;
457 StringBuilder result = new StringBuilder();
458 if (lowerLimit != null) {
459 result.append(lowerLimit);
460 result.append(" \u2264 ");
462 result.append(propertyName);
463 result.append(" \u2264 ");
464 result.append(upperLimit);
465 return result.toString();
469 private static Collection<Resource> elementsOfDiagram(ReadGraph graph, Resource diagram) throws DatabaseException {
470 if (graph.isInstanceOf(diagram, STR.Composite)) {
471 // Resource is a composite - get diagram
472 return elementsOfDiagram(graph, graph.getSingleObject(diagram, MOD.CompositeToDiagram));
475 Collection<Resource> elements = graph.getObjects(diagram, L0.ConsistsOf);
476 Collection<Resource> result = new ArrayList<>();
477 for (Resource r : elements)
478 if (graph.isInstanceOf(r, DIA.Element))
483 private Collection<Resource> filterElementsFrom(ReadGraph graph, Collection<Resource> elements) throws DatabaseException {
484 if (condition == null) return elements;
486 ArrayList<Resource> result = new ArrayList<>();
487 for (Resource r : elements) {
488 if (condition.match(graph, r))
495 private SelectionResult gather(ReadGraph graph, Resource model) throws DatabaseException {
496 return selector.select(graph, filterElementsFrom(graph, generator.generate(graph, model)));
501 public static abstract class Generator {
502 abstract Collection<Resource> generate(ReadGraph graph, Resource model) throws DatabaseException;
505 public static class ModelGenerator extends Generator {
507 Collection<Resource> generate(ReadGraph graph, Resource model) throws DatabaseException {
508 Resource conf = graph.syncRequest(new Configuration(model));
510 HashMap<Resource, Resource> fromMapped = new HashMap<Resource, Resource>();
512 // Iterate over diagrams
513 // Each model element is represented by the corresponding mapping element, if present
514 for (Resource comp : graph.getObjects(conf, L0.ConsistsOf)) {
515 if (!graph.isInstanceOf(comp, STR.Composite)) continue;
517 Resource diagram = graph.getPossibleObject(comp, MOD.CompositeToDiagram);
518 if (diagram != null) {
519 for (Resource elem : elementsOfDiagram(graph, diagram)) {
520 Resource mapped = graph.getPossibleObject(elem, DN.MappedComponent);
521 if (mapped != null) {
522 fromMapped.put(mapped, elem);
524 else if (!fromMapped.containsKey(elem)) {
525 fromMapped.put(elem, elem);
531 return new ArrayList<>(fromMapped.values());
535 public static class DiagramGenerator extends Generator {
536 public Resource diagram;
538 public DiagramGenerator(Resource diagram) {
539 this.diagram = diagram;
543 Collection<Resource> generate(ReadGraph graph, Resource model) throws DatabaseException {
544 return elementsOfDiagram(graph, diagram);
548 public static class ExplicitGenerator extends Generator {
549 public ExplicitGenerator(Collection<Resource> elements) {
550 this.elements = elements;
553 public Collection<Resource> elements;
556 Collection<Resource> generate(ReadGraph graph, Resource model) {
563 public static class SelectionResult {
564 public final Collection<Resource> elements;
565 public final int tailCount;
566 public final int tailSize;
568 public SelectionResult(Collection<Resource> elements, int tailCount, int tailSize) {
569 this.elements = elements;
570 this.tailCount = tailCount;
571 this.tailSize = tailSize;
575 public static abstract class Selector {
576 public Resource componentType = null;
578 abstract SelectionResult select(ReadGraph graph, Collection<Resource> elements);
580 Collection<Resource> filterElements(ReadGraph graph, Collection<Resource> elements) {
581 if (componentType == null)
584 Collection<Resource> selected = new HashSet<>(elements.size());
585 for (Resource r : elements) {
587 if (graph.hasStatement(r, DN.HasMapping, componentType))
589 } catch (DatabaseException e) {
590 // Just leave it out of the result
598 public static class All extends Selector {
603 SelectionResult select(ReadGraph graph, Collection<Resource> elements) {
604 Collection<Resource> selected = filterElements(graph, elements);
605 return new SelectionResult(selected, 0, 0);
609 public static class PropertySelector extends Selector {
610 public PropertySelector(boolean smallest, String propertyName, int resultCount) {
611 this.smallest = smallest;
612 this.propertyName = propertyName;
613 this.resultCount = resultCount;
616 public PropertySelector(ReadGraph graph, Resource resource) throws DatabaseException {
617 this.propertyName = graph.getRelatedValue(resource, ES.PropertySelector_HasSelectionPropertyName);
618 this.resultCount = graph.getRelatedValue(resource, ES.PropertySelector_HasResultCount);
619 this.smallest = graph.isInstanceOf(resource, ES.Selector_NLowest);
622 public boolean smallest;
623 public String propertyName;
624 public int resultCount;
627 SelectionResult select(ReadGraph graph, Collection<Resource> elements) {
628 elements = filterElements(graph, elements);
630 // Select sorting direction
631 Comparator<Pair<Resource, Double>> comparator = smallest ?
632 (p1, p2) -> Double.compare(p1.second, p2.second) :
633 (p1, p2) -> Double.compare(p1.second, p2.second);
635 // Get association list to property values
636 List<Pair<Resource, Double>> result2 = elements.stream()
637 .map(r -> Pair.make(r, getPropertyValue(graph, r, propertyName)))
638 .filter(t -> t.second != null)
640 .collect(Collectors.toList());
641 int count = Math.min(resultCount, result2.size());
643 // Count number of equal values at the end of the list
645 double tailValue = count > 0 ? result2.get(count-1).second : 0.0;
646 for (int i = count-1; i >= 0; i--) {
647 if (result2.get(i).second == tailValue)
653 // Count number of elements with value equal to the end of the list
654 int tailSize = tailCount;
655 for (int i = count; i < result2.size(); i++) {
656 if (result2.get(i).second == tailValue)
662 // Take first n items
663 if (count < result2.size()) {
664 result2 = result2.subList(0, resultCount);
667 // Map to list or resources
668 List<Resource> selection = result2.stream().map(p -> p.first).collect(Collectors.toList());
669 return new SelectionResult(selection, tailCount, tailSize);
675 public static abstract class Condition {
676 public Resource resource;
677 public boolean isInverse;
679 Condition(Resource r) {
684 Condition(ReadGraph graph, Resource r) throws DatabaseException {
686 isInverse = graph.hasStatement(r, ES.Condition_IsInverse, r);
689 public abstract boolean match(ReadGraph graph, Resource r) throws DatabaseException;
690 public Resource update(WriteGraph graph) throws DatabaseException {
691 assert(resource != null);
693 graph.claim(resource, ES.Condition_IsInverse, resource);
695 graph.deny(resource, ES.Condition_IsInverse, resource);
700 public static class PropertyCondition extends Condition {
701 public PropertyCondition(ReadGraph graph, Resource r) throws DatabaseException {
704 this.propertyName = graph.getRelatedValue(resource, ES.PropertyCondition_HasPropertyName);
705 this.lowerLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasLowerLimit);
706 this.upperLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasUpperLimit);
709 public PropertyCondition(Resource r, String propertyName, Double lowerLimit, Double upperLimit) {
712 this.propertyName = propertyName;
713 this.lowerLimit = lowerLimit;
714 this.upperLimit = upperLimit;
717 public String propertyName;
718 public Double lowerLimit;
719 public Double upperLimit;
722 public boolean match(ReadGraph graph, Resource r) {
723 Double value = getPropertyValue(graph, r, propertyName);
724 boolean result = value != null && (lowerLimit == null || value >= lowerLimit) && (upperLimit == null || value <= upperLimit);
725 return result ^ isInverse;
729 public Resource update(WriteGraph graph) throws DatabaseException {
730 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
731 Layer0 L0 = Layer0.getInstance(graph);
733 if (resource == null) {
734 resource = graph.newResource();
735 graph.claim(resource, L0.InstanceOf, ES.PropertyCondition);
740 graph.claimLiteral(resource, ES.PropertyCondition_HasPropertyName, propertyName);
741 if (lowerLimit != null)
742 graph.claimLiteral(resource, ES.PropertyCondition_HasLowerLimit, L0.Double, lowerLimit);
744 graph.deny(resource, ES.PropertyCondition_HasLowerLimit);
746 if (upperLimit != null)
747 graph.claimLiteral(resource, ES.PropertyCondition_HasUpperLimit, L0.Double, upperLimit);
749 graph.deny(resource, ES.PropertyCondition_HasUpperLimit);
754 public static class RegionCondition extends Condition {
755 public RegionCondition(Resource r, Resource regionResource, double[] region) {
757 this.region = region;
758 this.path = createPathForRegion(region);
759 this.regionResource = regionResource;
762 public RegionCondition(ReadGraph graph, Resource r) throws DatabaseException {
765 DiagramRegionsResource DR = DiagramRegionsResource.getInstance(graph);
766 this.regionResource = graph.getPossibleObject(resource, ES.RegionCondition_HasRegion);
767 this.region = regionResource != null ? graph.getRelatedValue(regionResource, DR.Region_area) : null;
768 this.path = createPathForRegion(region);
771 public static Path2D createPathForRegion(double[] region) {
772 Path2D path = new Path2D.Double();
773 if (region != null) {
774 double startX = region[0];
775 double startY = region[1];
776 path.moveTo(startX, startY);
777 for (int i = 2; i < region.length; i+=2)
778 path.lineTo(region[i], region[i+1]);
785 public Resource regionResource;
790 public boolean match(ReadGraph graph, Resource r) throws DatabaseException {
791 double[] transform = graph.getRelatedValue(r, DIA.HasTransform);
792 double x = transform[4];
793 double y = transform[5];
794 return path.contains(x, y) ^ isInverse;
798 public Resource update(WriteGraph graph) throws DatabaseException {
799 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
800 Layer0 L0 = Layer0.getInstance(graph);
802 if (resource == null) {
803 resource = graph.newResource();
804 graph.claim(resource, L0.InstanceOf, ES.RegionCondition);
809 graph.claim(resource, ES.RegionCondition_HasRegion, regionResource);
811 // Re-read region data to match DB
812 DiagramRegionsResource DR = DiagramRegionsResource.getInstance(graph);
813 this.region = regionResource != null ? graph.getRelatedValue(regionResource, DR.Region_area, Bindings.DOUBLE_ARRAY) : null;
814 this.path = createPathForRegion(region);
820 public static class RouteCondition extends Condition {
821 public RouteCondition(Resource r, Resource routeResource, Set<Resource> routePoints) {
823 this.routePoints = routePoints;
824 this.routeResource = routeResource;
827 public RouteCondition(ReadGraph graph, Resource r) throws DatabaseException {
829 this.routeResource = graph.getPossibleObject(resource, ES.RouteCondition_HasRoute);
830 this.routePoints = getRoutePoints(graph, routeResource);
833 public static Set<Resource> getRoutePoints(ReadGraph graph, Resource routeResource) throws DatabaseException {
834 return routeResource != null ?
835 new HashSet<>(ListUtils.toList(graph, routeResource)) :
836 Collections.emptySet();
839 public Resource routeResource;
840 Set<Resource> routePoints;
843 public boolean match(ReadGraph graph, Resource r) throws DatabaseException {
844 return routePoints.contains(r) ^ isInverse;
848 public Resource update(WriteGraph graph) throws DatabaseException {
849 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
850 Layer0 L0 = Layer0.getInstance(graph);
852 if (resource == null) {
853 resource = graph.newResource();
854 graph.claim(resource, L0.InstanceOf, ES.RouteCondition);
859 if (routeResource != null)
860 graph.claim(resource, ES.RouteCondition_HasRoute, routeResource);
862 this.routePoints = getRoutePoints(graph, routeResource);
868 public static class AggregateCondition extends Condition {
869 public static enum Type { DISJUNCTION, CONJUNCTION, NEGATION };
871 public AggregateCondition(Resource r, Type type, List<Condition> conditions) {
874 this.conditions = conditions;
877 public AggregateCondition(ReadGraph graph, Resource r) throws DatabaseException {
879 Collection<Resource> conditionResources = graph.getObjects(resource, ES.HasSubcondition);
880 conditions = new ArrayList<>(conditionResources.size());
881 for (Resource c : conditionResources) {
882 conditions.add(buildCondition(graph, c));
884 if (graph.isInstanceOf(resource, ES.Conjunction))
885 this.type = AggregateCondition.Type.CONJUNCTION;
886 else if (graph.isInstanceOf(resource, ES.Negation))
887 this.type = AggregateCondition.Type.NEGATION;
888 else if (graph.isInstanceOf(resource, ES.Disjunction))
889 this.type = AggregateCondition.Type.DISJUNCTION;
891 throw new IllegalArgumentException("Unknown aggreate condition type " + graph.getURI(graph.getSingleType(resource)));
895 public List<Condition> conditions;
898 public boolean match(ReadGraph graph, Resource r) throws DatabaseException {
899 return doMatch(graph, r) ^ isInverse;
902 private boolean doMatch(ReadGraph graph, Resource r) throws DatabaseException {
905 for (Condition c : conditions)
906 if (c.match(graph, r)) return true;
909 for (Condition c : conditions)
910 if (!c.match(graph, r)) return false;
913 for (Condition c : conditions)
914 if (c.match(graph, r)) return false;
918 throw new IllegalArgumentException("Unknown aggregate condition type " + type);
923 public Resource update(WriteGraph graph) throws DatabaseException {
924 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
925 Layer0 L0 = Layer0.getInstance(graph);
927 if (resource == null) {
928 resource = graph.newResource();
930 graph.deny(resource, L0.InstanceOf);
931 graph.deny(resource, ES.HasSubcondition);
937 type = ES.Conjunction; break;
939 type = ES.Disjunction; break;
941 type = ES.Negation; break;
943 throw new IllegalStateException("Unknown condition type " + this.type);
946 graph.claim(resource, L0.InstanceOf, type);
950 for (Condition c : conditions) {
951 graph.claim(resource, ES.HasSubcondition, c.update(graph));
958 public static class ElementSelectorQuery extends ResourceRead<ElementSelector> {
959 public ElementSelectorQuery(Resource resource) {
964 public ElementSelector perform(ReadGraph graph) throws DatabaseException {
965 return new ElementSelector(graph, resource);
969 public final static class SelectionExpressionRequest extends ResourceRead<String> {
970 public SelectionExpressionRequest(Resource condition) {
975 public String perform(ReadGraph graph) throws DatabaseException {
976 return ElementSelector.buildExpression(graph, resource);
980 public static final class SelectionConditionRequest extends ResourceRead<Condition> {
981 public SelectionConditionRequest(Resource resource) {
986 public Condition perform(ReadGraph graph) throws DatabaseException {
987 return buildCondition(graph, resource);