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 private float[] color;
61 static Logger LOG = LoggerFactory.getLogger(ElementSelector.class);
63 static ElementSelectionResource ES;
65 static StructuralResource2 STR;
66 static ModelingResources MOD;
67 static DiagramResource DIA;
68 static DistrictNetworkResource DN;
70 private static Logger LOGGER = LoggerFactory.getLogger(ElementSelector.class);
72 ElementSelector(ReadGraph graph, Resource resource) throws DatabaseException {
75 L0 = Layer0.getInstance(graph);
76 ES = ElementSelectionResource.getInstance(graph);
77 STR = StructuralResource2.getInstance(graph);
78 MOD = ModelingResources.getInstance(graph);
79 DIA = DiagramResource.getInstance(graph);
80 DN = DistrictNetworkResource.getInstance(graph);
82 this.resource = resource;
84 this.name = graph.getRelatedValue(resource, L0.HasLabel);
85 this.expression = getExpression(graph, resource);
87 float[] color = graph.getPossibleRelatedValue(resource, ES.Selection_HasHighlightColor);
89 } catch (DatabaseException e) {
90 LOG.error("Error reading element selector", e);
96 * Instantiate an element selector object for an ES.Selection resource.
98 public static ElementSelector getSelector(RequestProcessor graph, Resource resource) throws DatabaseException {
99 return graph.syncRequest(new ElementSelectorQuery(resource));
103 * Get an SQL-like textual description of an ES.Selection resource.
105 public static String getExpression(RequestProcessor graph, Resource resource) throws DatabaseException {
106 return graph.syncRequest(new SelectionExpressionRequest(resource));
110 * Get a Java object representation of an ES.Condition resource.
112 public static Condition getCondition(RequestProcessor graph, Resource condition) throws DatabaseException {
113 return graph.syncRequest(new SelectionConditionRequest(condition));
117 * Get the name of the element selector.
119 public String getName() {
124 * Get a textual SQL-like description of the element selector.
126 public String getExpression() {
131 * Get the resource that this selector represents.
133 public Resource getResource() {
138 * Get the generator component. Use {@link #buildSelection(ReadGraph)} to make it available first.
140 public Generator getGenerator() {
145 * Get the selector component. Use {@link #buildSelection(ReadGraph)} to make it available first.
147 public Selector getSelector() {
152 * Get the condition component. Use {@link #buildSelection(ReadGraph)} to make it available first.
154 public Condition getCondition() {
159 * Get the selection highlight color as a four element BGRA array.
161 public float[] getColor() {
168 * @throws DatabaseException
170 public void buildSelection(ReadGraph graph) throws DatabaseException {
171 Resource selector = graph.getSingleObject(resource, ES.Selection_HasSelector);
172 Resource generator = graph.getSingleObject(resource, ES.Selection_HasGenerator);
173 Resource condition = graph.getPossibleObject(resource, ES.Selection_HasCondition);
175 this.selector = buildSelector(graph, selector);
176 this.generator = buildGenerator(graph, generator);
177 this.condition = buildCondition(graph, condition);
180 public static Map<Resource, String> findDiagrams() {
182 return Simantics.getSession().syncRequest(new Read<Map<Resource, String>>() {
184 public Map<Resource, String> perform(ReadGraph graph) throws DatabaseException {
185 Layer0 L0 = Layer0.getInstance(graph);
186 StructuralResource2 STR = StructuralResource2.getInstance(graph);
187 DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
188 ModelingResources MOD = ModelingResources.getInstance(graph);
190 Map<Resource, String> result = new HashMap<>();
191 Resource model = graph.syncRequest(new PossibleActiveModel(Simantics.getProjectResource()));
192 List<Resource> composites = QueryIndexUtils.searchByType(graph, model, STR.Composite);
193 for (Resource r : composites) {
195 Resource diagram = graph.getPossibleObject(r, MOD.CompositeToDiagram);
196 if (diagram == null || !graph.isInstanceOf(diagram, DN.Diagram))
199 // Filter out user component diagrams
200 Resource parent = graph.getPossibleObject(r, L0.PartOf);
201 if (parent == null || graph.isInheritedFrom(parent, STR.Component))
204 result.put(r, graph.getRelatedValue(r, L0.HasName));
210 } catch (DatabaseException e) {
211 LOGGER.error("Query for model diagrams failed", e);
212 return Collections.emptyMap();
216 public static Variable getVariableForElement(ReadGraph graph, Resource element) throws DatabaseException {
217 Resource component = graph.getPossibleObject(element, MOD.ElementToComponent);
218 if (component != null) {
219 Variable var = Variables.getVariable(graph, component);
220 RVI realRvi = var.getRVI(graph);
222 for (Resource activeModel : graph.syncRequest(new ActiveModels(Simantics.getProjectResource()))) {
223 for (Variable run : graph.syncRequest(new ActiveRuns(activeModel))) {
224 Variable v = realRvi.resolvePossible(graph, run);
229 Variable configuration = Variables.getPossibleConfigurationContext(graph, activeModel);
230 if (configuration != null) {
231 Variable v = realRvi.resolvePossible(graph, configuration);
242 public static Double getPropertyValue(ReadGraph graph, Resource element, String propertyName) {
244 Variable v = getVariableForElement(graph, element);
246 Number value = v.getPossiblePropertyValue(graph, propertyName);
248 return value.doubleValue();
251 // No property found - try possible mapped element property as well
252 Resource mappedElement = graph.getPossibleObject(element, DN.MappedComponent);
253 if (mappedElement != null)
254 return getPropertyValue(graph, mappedElement, propertyName);
256 catch (DatabaseException e) {
262 public SelectionResult selectElementsFrom(ReadGraph graph, Resource model) throws DatabaseException {
263 if (selector == null) {
264 buildSelection(graph);
267 return gather(graph, model);
270 private static Generator buildGenerator(ReadGraph graph, Resource resource) throws DatabaseException {
271 if (!graph.isInstanceOf(resource, ES.Generator))
272 throw new IllegalArgumentException("Resource " + resource + " is not a valid generator");
274 if (graph.isInstanceOf(resource, ES.Generator_Model))
275 return new ModelGenerator();
276 else if (graph.isInstanceOf(resource, ES.Generator_Diagram))
277 return new DiagramGenerator(graph.getSingleObject(resource, ES.Generator_HasDiagram));
278 else if (graph.isInstanceOf(resource, ES.Generator_Explicit))
279 return new ExplicitGenerator(graph.getObjects(resource, ES.Generator_HasSelectedElement));
281 throw new IllegalArgumentException("Unknown generator type " + graph.getURI(graph.getSingleType(resource)));
284 private static Selector buildSelector(ReadGraph graph, Resource resource) throws DatabaseException {
285 if (!graph.isInstanceOf(resource, ES.Selector))
286 throw new IllegalArgumentException("Resource " + resource + " is not a valid selector");
289 if (graph.isInstanceOf(resource, ES.Selector_All))
291 else if (graph.isInstanceOf(resource, ES.PropertySelector))
292 s = new PropertySelector(graph, resource);
294 throw new IllegalArgumentException("Unknown selector type " + graph.getURI(graph.getSingleType(resource)));
296 Resource mapping = graph.getPossibleObject(resource, ES.Selector_HasMapping);
297 s.componentType = mapping;
302 private static Condition buildCondition(ReadGraph graph, Resource resource) throws DatabaseException {
303 if (resource == null)
306 if (!graph.isInstanceOf(resource, ES.Condition))
307 throw new IllegalArgumentException("Resource " + resource + " is not a valid condition");
310 if (graph.isInstanceOf(resource, ES.PropertyCondition))
311 cond = new PropertyCondition(graph, resource);
312 else if (graph.isInstanceOf(resource, ES.RegionCondition))
313 cond = new RegionCondition(graph, resource);
314 else if (graph.isInstanceOf(resource, ES.RouteCondition))
315 cond = new RouteCondition(graph, resource);
316 else if (graph.isInstanceOf(resource, ES.AggregateCondition))
317 cond = new AggregateCondition(graph, resource);
319 throw new IllegalArgumentException("Unknown condition type " + graph.getURI(graph.getSingleType(resource)));
324 private static String buildExpression(ReadGraph graph, Resource r) throws DatabaseException {
325 if (graph.isInstanceOf(r, ES.Selection))
326 return buildSelectionExpression(graph, r);
327 else if (graph.isInstanceOf(r, ES.Condition))
328 return buildConditionExpression(graph, r);
329 else if (graph.isInstanceOf(r, ES.Selector))
330 return buildSelectorExpression(graph, r);
331 else if (graph.isInstanceOf(r, ES.Generator))
332 return buildGeneratorExpression(graph, r);
334 throw new DatabaseException("Unsupported resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
337 private static String buildSelectionExpression(ReadGraph graph, Resource r) throws DatabaseException,
338 NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException {
339 String exp = "select " + getExpression(graph, graph.getSingleObject(r, ES.Selection_HasSelector)) +
340 " from " + getExpression(graph, graph.getSingleObject(r, ES.Selection_HasGenerator));
342 Resource cond = graph.getPossibleObject(r, ES.Selection_HasCondition);
343 return cond != null ? exp + " where {" + getExpression(graph, cond) + "}" : exp;
346 private static String buildGeneratorExpression(ReadGraph graph, Resource r)
347 throws ServiceException, NoSingleResultException, DoesNotContainValueException,
348 ManyObjectsForFunctionalRelationException, DatabaseException, AssumptionException, ValidationException {
349 if (graph.isInstanceOf(r, ES.Generator_Model)) {
352 else if (graph.isInstanceOf(r, ES.Generator_Diagram)) {
353 return "diagram \"" + graph.getRelatedValue(graph.getSingleObject(r, ES.Generator_HasDiagram), L0.HasName) + "\"";
355 else if (graph.isInstanceOf(r, ES.Generator_Explicit)) {
356 return "<list of " + graph.getObjects(r, ES.Generator_HasSelectedElement).size() + " elements>";
359 throw new DatabaseException("Unsupported generator resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
363 private static String buildSelectorExpression(ReadGraph graph, Resource r)
364 throws ServiceException, NoSingleResultException, DoesNotContainValueException, DatabaseException,
365 AssumptionException, ValidationException, ManyObjectsForFunctionalRelationException {
367 if (graph.isInstanceOf(r, ES.Selector_All)) {
370 else if (graph.isInstanceOf(r, ES.PropertySelector)) {
371 Integer count = graph.getRelatedValue(r, ES.PropertySelector_HasResultCount);
372 exp = count.toString();
375 throw new DatabaseException("Unsupported selector resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
378 Resource mapping = graph.getPossibleObject(r, ES.Selector_HasMapping);
379 if (mapping != null) {
380 String name = graph.getRelatedValue2(mapping, L0.HasName);
381 exp = exp + " " + name;
383 exp = exp + " elements";
386 if (graph.isInstanceOf(r, ES.PropertySelector)) {
388 if (graph.isInstanceOf(r, ES.Selector_NLowest))
390 else if (graph.isInstanceOf(r, ES.Selector_NHighest))
393 throw new DatabaseException("Unsupported property selector resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
395 String name = graph.getRelatedValue(r, ES.PropertySelector_HasSelectionPropertyName);
396 exp = exp + " with " + op + " " + name;
402 private static String buildConditionExpression(ReadGraph graph, Resource r) throws ServiceException,
403 DatabaseException, NoSingleResultException, ManyObjectsForFunctionalRelationException,
404 DoesNotContainValueException, AssumptionException, ValidationException {
406 boolean isInverse = graph.hasStatement(r, ES.Condition_IsInverse, r);
407 if (graph.isInstanceOf(r, ES.PropertyCondition)) {
408 result = buildPropertyConditionExpression(graph, r);
410 else if (graph.isInstanceOf(r, ES.RegionCondition)) {
411 result = buildRegionConditionExpression(graph, r);
413 else if (graph.isInstanceOf(r, ES.RouteCondition)) {
414 result = buildRouteConditionExpression(graph, r);
416 else if (graph.isInstanceOf(r, ES.AggregateCondition)) {
417 // This handles isInverse internally
418 return buildAggregateConditionExpression(graph, r, isInverse);
421 throw new DatabaseException("Unsupported condition resource type <" + graph.getURI(graph.getSingleType(r)) + ">");
425 result = "not {" + result + "}";
430 private static String buildAggregateConditionExpression(ReadGraph graph, Resource r, boolean isInverse)
431 throws ServiceException, DatabaseException {
433 String op = graph.isInstanceOf(r, ES.Conjunction) ? " and " : " or ";
434 List<String> exps = new ArrayList<>();
435 Collection<Resource> objects = graph.getObjects(r, ES.HasSubcondition);
436 for (Resource c : objects) {
437 String exp = getExpression(graph, c);
438 exps.add(objects.size() > 1 ? "{" + exp + "}" : exp);
440 result = String.join(op, exps);
441 if (graph.isInstanceOf(r, ES.Negation) ^ isInverse)
442 result = "not {" + result + "}";
446 private static String buildRouteConditionExpression(ReadGraph graph, Resource r) throws NoSingleResultException,
447 ManyObjectsForFunctionalRelationException, ServiceException, DoesNotContainValueException {
449 Resource route = graph.getSingleObject(r, ES.RouteCondition_HasRoute);
450 String name = graph.getRelatedValue(route, L0.HasLabel);
451 result = "in route " + name;
455 private static String buildRegionConditionExpression(ReadGraph graph, Resource r) throws NoSingleResultException,
456 ManyObjectsForFunctionalRelationException, ServiceException, DoesNotContainValueException {
458 Resource region = graph.getSingleObject(r, ES.RegionCondition_HasRegion);
459 String name = graph.getRelatedValue(region, L0.HasLabel);
460 result = "in region " + name;
464 private static String buildPropertyConditionExpression(ReadGraph graph, Resource r) throws DatabaseException {
465 String propertyName = graph.getRelatedValue(r, ES.PropertyCondition_HasPropertyName);
466 Double lowerLimit = graph.getPossibleRelatedValue(r, ES.PropertyCondition_HasLowerLimit);
467 Double upperLimit = graph.getPossibleRelatedValue(r, ES.PropertyCondition_HasUpperLimit);
468 if (upperLimit == null) {
469 if (lowerLimit == null) {
470 return "has property " + propertyName;
472 return propertyName + " \u2265 " + lowerLimit;
475 StringBuilder result = new StringBuilder();
476 if (lowerLimit != null) {
477 result.append(lowerLimit);
478 result.append(" \u2264 ");
480 result.append(propertyName);
481 result.append(" \u2264 ");
482 result.append(upperLimit);
483 return result.toString();
487 private static Collection<Resource> elementsOfDiagram(ReadGraph graph, Resource diagram) throws DatabaseException {
488 if (graph.isInstanceOf(diagram, STR.Composite)) {
489 // Resource is a composite - get diagram
490 return elementsOfDiagram(graph, graph.getSingleObject(diagram, MOD.CompositeToDiagram));
493 Collection<Resource> elements = graph.getObjects(diagram, L0.ConsistsOf);
494 Collection<Resource> result = new ArrayList<>();
495 for (Resource r : elements)
496 if (graph.isInstanceOf(r, DIA.Element))
501 private Collection<Resource> filterElementsFrom(ReadGraph graph, Collection<Resource> elements) throws DatabaseException {
502 if (condition == null) return elements;
504 ArrayList<Resource> result = new ArrayList<>();
505 for (Resource r : elements) {
506 if (condition.match(graph, r))
513 private SelectionResult gather(ReadGraph graph, Resource model) throws DatabaseException {
514 return selector.select(graph, filterElementsFrom(graph, generator.generate(graph, model)));
519 public static abstract class Generator {
520 abstract Collection<Resource> generate(ReadGraph graph, Resource model) throws DatabaseException;
523 public static class ModelGenerator extends Generator {
525 Collection<Resource> generate(ReadGraph graph, Resource model) throws DatabaseException {
526 Resource conf = graph.syncRequest(new Configuration(model));
528 HashMap<Resource, Resource> fromMapped = new HashMap<Resource, Resource>();
530 // Iterate over diagrams
531 // Each model element is represented by the corresponding mapping element, if present
532 for (Resource comp : graph.getObjects(conf, L0.ConsistsOf)) {
533 if (!graph.isInstanceOf(comp, STR.Composite)) continue;
535 Resource diagram = graph.getPossibleObject(comp, MOD.CompositeToDiagram);
536 if (diagram != null) {
537 for (Resource elem : elementsOfDiagram(graph, diagram)) {
538 Resource mapped = graph.getPossibleObject(elem, DN.MappedComponent);
539 if (mapped != null) {
540 fromMapped.put(mapped, elem);
542 else if (!fromMapped.containsKey(elem)) {
543 fromMapped.put(elem, elem);
549 return new ArrayList<>(fromMapped.values());
553 public static class DiagramGenerator extends Generator {
554 public Resource diagram;
556 public DiagramGenerator(Resource diagram) {
557 this.diagram = diagram;
561 Collection<Resource> generate(ReadGraph graph, Resource model) throws DatabaseException {
562 return elementsOfDiagram(graph, diagram);
566 public static class ExplicitGenerator extends Generator {
567 public ExplicitGenerator(Collection<Resource> elements) {
568 this.elements = elements;
571 public Collection<Resource> elements;
574 Collection<Resource> generate(ReadGraph graph, Resource model) {
581 public static class SelectionResult {
582 public final Collection<Resource> elements;
583 public final int tailCount;
584 public final int tailSize;
586 public SelectionResult(Collection<Resource> elements, int tailCount, int tailSize) {
587 this.elements = elements;
588 this.tailCount = tailCount;
589 this.tailSize = tailSize;
593 public static abstract class Selector {
594 public Resource componentType = null;
596 abstract SelectionResult select(ReadGraph graph, Collection<Resource> elements);
598 Collection<Resource> filterElements(ReadGraph graph, Collection<Resource> elements) {
599 if (componentType == null)
602 Collection<Resource> selected = new HashSet<>(elements.size());
603 for (Resource r : elements) {
605 if (graph.hasStatement(r, DN.HasMapping, componentType))
607 } catch (DatabaseException e) {
608 // Just leave it out of the result
616 public static class All extends Selector {
621 SelectionResult select(ReadGraph graph, Collection<Resource> elements) {
622 Collection<Resource> selected = filterElements(graph, elements);
623 return new SelectionResult(selected, 0, 0);
627 public static class PropertySelector extends Selector {
628 public PropertySelector(boolean smallest, String propertyName, int resultCount) {
629 this.smallest = smallest;
630 this.propertyName = propertyName;
631 this.resultCount = resultCount;
634 public PropertySelector(ReadGraph graph, Resource resource) throws DatabaseException {
635 this.propertyName = graph.getRelatedValue(resource, ES.PropertySelector_HasSelectionPropertyName);
636 this.resultCount = graph.getRelatedValue(resource, ES.PropertySelector_HasResultCount);
637 this.smallest = graph.isInstanceOf(resource, ES.Selector_NLowest);
640 public boolean smallest;
641 public String propertyName;
642 public int resultCount;
645 SelectionResult select(ReadGraph graph, Collection<Resource> elements) {
646 elements = filterElements(graph, elements);
648 // Select sorting direction
649 Comparator<Pair<Resource, Double>> comparator = smallest ?
650 (p1, p2) -> Double.compare(p1.second, p2.second) :
651 (p1, p2) -> Double.compare(p1.second, p2.second);
653 // Get association list to property values
654 List<Pair<Resource, Double>> result2 = elements.stream()
655 .map(r -> Pair.make(r, getPropertyValue(graph, r, propertyName)))
656 .filter(t -> t.second != null)
658 .collect(Collectors.toList());
659 int count = Math.min(resultCount, result2.size());
661 // Count number of equal values at the end of the list
663 double tailValue = count > 0 ? result2.get(count-1).second : 0.0;
664 for (int i = count-1; i >= 0; i--) {
665 if (result2.get(i).second == tailValue)
671 // Count number of elements with value equal to the end of the list
672 int tailSize = tailCount;
673 for (int i = count; i < result2.size(); i++) {
674 if (result2.get(i).second == tailValue)
680 // Take first n items
681 if (count < result2.size()) {
682 result2 = result2.subList(0, resultCount);
685 // Map to list or resources
686 List<Resource> selection = result2.stream().map(p -> p.first).collect(Collectors.toList());
687 return new SelectionResult(selection, tailCount, tailSize);
693 public static abstract class Condition {
694 public Resource resource;
695 public boolean isInverse;
697 Condition(Resource r) {
702 Condition(ReadGraph graph, Resource r) throws DatabaseException {
704 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
705 isInverse = graph.hasStatement(r, ES.Condition_IsInverse, r);
708 public abstract boolean match(ReadGraph graph, Resource r) throws DatabaseException;
709 public Resource update(WriteGraph graph) throws DatabaseException {
710 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
712 assert(resource != null);
714 graph.claim(resource, ES.Condition_IsInverse, resource);
716 graph.deny(resource, ES.Condition_IsInverse, resource);
721 public static class PropertyCondition extends Condition {
722 public PropertyCondition(ReadGraph graph, Resource r) throws DatabaseException {
725 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
726 this.propertyName = graph.getRelatedValue(resource, ES.PropertyCondition_HasPropertyName);
727 this.lowerLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasLowerLimit);
728 this.upperLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasUpperLimit);
731 public PropertyCondition(Resource r, String propertyName, Double lowerLimit, Double upperLimit) {
734 this.propertyName = propertyName;
735 this.lowerLimit = lowerLimit;
736 this.upperLimit = upperLimit;
739 public String propertyName;
740 public Double lowerLimit;
741 public Double upperLimit;
744 public boolean match(ReadGraph graph, Resource r) {
745 Double value = getPropertyValue(graph, r, propertyName);
746 boolean result = value != null && (lowerLimit == null || value >= lowerLimit) && (upperLimit == null || value <= upperLimit);
747 return result ^ isInverse;
751 public Resource update(WriteGraph graph) throws DatabaseException {
752 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
753 Layer0 L0 = Layer0.getInstance(graph);
755 if (resource == null) {
756 resource = graph.newResource();
757 graph.claim(resource, L0.InstanceOf, ES.PropertyCondition);
762 graph.claimLiteral(resource, ES.PropertyCondition_HasPropertyName, propertyName);
763 if (lowerLimit != null)
764 graph.claimLiteral(resource, ES.PropertyCondition_HasLowerLimit, L0.Double, lowerLimit);
766 graph.deny(resource, ES.PropertyCondition_HasLowerLimit);
768 if (upperLimit != null)
769 graph.claimLiteral(resource, ES.PropertyCondition_HasUpperLimit, L0.Double, upperLimit);
771 graph.deny(resource, ES.PropertyCondition_HasUpperLimit);
776 public static class RegionCondition extends Condition {
777 public RegionCondition(Resource r, Resource regionResource, double[] region) {
779 this.region = region;
780 this.path = createPathForRegion(region);
781 this.regionResource = regionResource;
784 public RegionCondition(ReadGraph graph, Resource r) throws DatabaseException {
787 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
788 DiagramRegionsResource DR = DiagramRegionsResource.getInstance(graph);
789 this.regionResource = graph.getPossibleObject(resource, ES.RegionCondition_HasRegion);
790 this.region = regionResource != null ? graph.getRelatedValue(regionResource, DR.Region_area) : null;
791 this.path = createPathForRegion(region);
794 public static Path2D createPathForRegion(double[] region) {
795 Path2D path = new Path2D.Double();
796 if (region != null) {
797 double startX = region[0];
798 double startY = region[1];
799 path.moveTo(startX, startY);
800 for (int i = 2; i < region.length; i+=2)
801 path.lineTo(region[i], region[i+1]);
808 public Resource regionResource;
813 public boolean match(ReadGraph graph, Resource r) throws DatabaseException {
814 double[] transform = graph.getRelatedValue(r, DIA.HasTransform);
815 double x = transform[4];
816 double y = transform[5];
817 return path.contains(x, y) ^ isInverse;
821 public Resource update(WriteGraph graph) throws DatabaseException {
822 Layer0 L0 = Layer0.getInstance(graph);
823 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
824 DiagramRegionsResource DR = DiagramRegionsResource.getInstance(graph);
826 if (resource == null) {
827 resource = graph.newResource();
828 graph.claim(resource, L0.InstanceOf, ES.RegionCondition);
833 graph.claim(resource, ES.RegionCondition_HasRegion, regionResource);
835 // Re-read region data to match DB
836 this.region = regionResource != null ? graph.getRelatedValue(regionResource, DR.Region_area, Bindings.DOUBLE_ARRAY) : null;
837 this.path = createPathForRegion(region);
843 public static class RouteCondition extends Condition {
844 public RouteCondition(Resource r, Resource routeResource, Set<Resource> routePoints) {
846 this.routePoints = routePoints;
847 this.routeResource = routeResource;
850 public RouteCondition(ReadGraph graph, Resource r) throws DatabaseException {
852 this.routeResource = graph.getPossibleObject(resource, ES.RouteCondition_HasRoute);
853 this.routePoints = getRoutePoints(graph, routeResource);
856 public static Set<Resource> getRoutePoints(ReadGraph graph, Resource routeResource) throws DatabaseException {
857 return routeResource != null ?
858 new HashSet<>(ListUtils.toList(graph, routeResource)) :
859 Collections.emptySet();
862 public Resource routeResource;
863 Set<Resource> routePoints;
866 public boolean match(ReadGraph graph, Resource r) throws DatabaseException {
867 return routePoints.contains(r) ^ isInverse;
871 public Resource update(WriteGraph graph) throws DatabaseException {
872 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
873 Layer0 L0 = Layer0.getInstance(graph);
875 if (resource == null) {
876 resource = graph.newResource();
877 graph.claim(resource, L0.InstanceOf, ES.RouteCondition);
882 if (routeResource != null)
883 graph.claim(resource, ES.RouteCondition_HasRoute, routeResource);
885 this.routePoints = getRoutePoints(graph, routeResource);
891 public static class AggregateCondition extends Condition {
892 public static enum Type { DISJUNCTION, CONJUNCTION, NEGATION };
894 public AggregateCondition(Resource r, Type type, List<Condition> conditions) {
897 this.conditions = conditions;
900 public AggregateCondition(ReadGraph graph, Resource r) throws DatabaseException {
902 Collection<Resource> conditionResources = graph.getObjects(resource, ES.HasSubcondition);
903 conditions = new ArrayList<>(conditionResources.size());
904 for (Resource c : conditionResources) {
905 conditions.add(buildCondition(graph, c));
907 if (graph.isInstanceOf(resource, ES.Conjunction))
908 this.type = AggregateCondition.Type.CONJUNCTION;
909 else if (graph.isInstanceOf(resource, ES.Negation))
910 this.type = AggregateCondition.Type.NEGATION;
911 else if (graph.isInstanceOf(resource, ES.Disjunction))
912 this.type = AggregateCondition.Type.DISJUNCTION;
914 throw new IllegalArgumentException("Unknown aggreate condition type " + graph.getURI(graph.getSingleType(resource)));
918 public List<Condition> conditions;
921 public boolean match(ReadGraph graph, Resource r) throws DatabaseException {
922 return doMatch(graph, r) ^ isInverse;
925 private boolean doMatch(ReadGraph graph, Resource r) throws DatabaseException {
928 for (Condition c : conditions)
929 if (c.match(graph, r)) return true;
932 for (Condition c : conditions)
933 if (!c.match(graph, r)) return false;
936 for (Condition c : conditions)
937 if (c.match(graph, r)) return false;
941 throw new IllegalArgumentException("Unknown aggregate condition type " + type);
946 public Resource update(WriteGraph graph) throws DatabaseException {
947 Layer0 L0 = Layer0.getInstance(graph);
948 ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
950 if (resource == null) {
951 resource = graph.newResource();
953 graph.deny(resource, L0.InstanceOf);
954 graph.deny(resource, ES.HasSubcondition);
960 type = ES.Conjunction; break;
962 type = ES.Disjunction; break;
964 type = ES.Negation; break;
966 throw new IllegalStateException("Unknown condition type " + this.type);
969 graph.claim(resource, L0.InstanceOf, type);
973 for (Condition c : conditions) {
974 graph.claim(resource, ES.HasSubcondition, c.update(graph));
981 public static class ElementSelectorQuery extends ResourceRead<ElementSelector> {
982 public ElementSelectorQuery(Resource resource) {
987 public ElementSelector perform(ReadGraph graph) throws DatabaseException {
988 return new ElementSelector(graph, resource);
992 public final static class SelectionExpressionRequest extends ResourceRead<String> {
993 public SelectionExpressionRequest(Resource condition) {
998 public String perform(ReadGraph graph) throws DatabaseException {
999 return ElementSelector.buildExpression(graph, resource);
1003 public static final class SelectionConditionRequest extends ResourceRead<Condition> {
1004 public SelectionConditionRequest(Resource resource) {
1009 public Condition perform(ReadGraph graph) throws DatabaseException {
1010 return buildCondition(graph, resource);