package application.simulator; import com.mxgraph.model.mxGraphModel; import com.mxgraph.view.mxGraph; import models.dataConstraintModel.ResourcePath; import simulator.Resource; import simulator.ResourceIdentifier; import simulator.Simulator; import simulator.SystemState; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; public class SimulationLayout { // Hold the division level for each resource HashMap<ResourceIdentifier,Integer> divisionLevelMap = new HashMap<>(); // Hold the scaling factor for each resource HashMap<ResourceIdentifier,Double> resourceScaleMap = new HashMap<>(); int maxDivisionLevel = 1; public final double BASE_WIDTH = 720; public final double BASE_HEIGHT = BASE_WIDTH/2; public final double MARGIN_SCALE = 0.92; SystemState systemState; public SimulationLayout(SystemState systemState){ this.systemState = systemState; // Calculate the division level for each resource for (Resource res:systemState.getRootResources()) { setDivisionLevel(divisionLevelMap, res.getResourceIdentifier(), 1); } // Calculate the scaling factor for each resource for (ResourceIdentifier res:divisionLevelMap.keySet()) { double scale = (double) maxDivisionLevel / divisionLevelMap.get(res); resourceScaleMap.put(res, scale); } } public double getScale(ResourceIdentifier resource){ return resourceScaleMap.get(resource); } public double getDivision(ResourceIdentifier resource){ return divisionLevelMap.get(resource); } public int getMaxDivisionLevel() { return maxDivisionLevel; } public boolean isExistResource(ResourceIdentifier resourceIdentifier){ return divisionLevelMap.containsKey(resourceIdentifier); } private void setDivisionLevel(HashMap<ResourceIdentifier,Integer> resourceSet, ResourceIdentifier resource, int childCount){ int divisionLevel; if(resourceSet.get(resource.getParent()) == null){ divisionLevel = 1; }else{ divisionLevel = resourceSet.get(resource.getParent()) * childCount; } if (divisionLevel > maxDivisionLevel)maxDivisionLevel = divisionLevel; resourceSet.put(resource,divisionLevel); Collection<Resource> identifiers = systemState.getResource(resource).getChildren(); if (identifiers != null) { for (Resource child:identifiers) { setDivisionLevel(resourceSet, child.getResourceIdentifier(), identifiers.size()); } } } /** * * Draw an object corresponding to the target resource on the mxGraph. * @param graph The mxGraph for drawing. * @param parent The parent object of the target resource. * @param resourceIdentifier The ID of the target resource. * @param index The index. * @param length The number of sibling resources of the target resource. * @return The drawing object of the target resource. */ private Object setLayout(mxGraph graph,Object parent, ResourceIdentifier resourceIdentifier,double index, double length){ double width, height, x, y; double parentWidth = graph.getCellGeometry(parent).getWidth(); double parentHeight = graph.getCellGeometry(parent).getHeight(); width = parentWidth / length * MARGIN_SCALE; height = width/2; x = parentWidth * (index - 1)/length + (parentWidth/length)*(1-MARGIN_SCALE)/2; // Process to avoid hiding the parent's resource name if ((int)length == 1) { y = 20; height -=20; } else { y = parentHeight/2 - height/2; } Object result = graph.insertVertex(parent, null, resourceIdentifier.toString(), x, y, width, height, "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); System.out.println(result); return result; } public mxGraph constructSimulateGraph(mxGraph graph, Simulator simulator){ ((mxGraphModel) graph.getModel()).clear(); Object parent = graph.getDefaultParent(); graph.getModel().beginUpdate(); try { Map<Resource, Object> resources = new HashMap<>(); int i = 0; int childCount = simulator.getCurState().getRootResources().size(); // create resource vertices for (Resource resNode: simulator.getCurState().getRootResources()) { double scale = this.getScale(resNode.getResourceIdentifier()); double maxDiv = this.getMaxDivisionLevel(); double w = this.BASE_WIDTH * scale / maxDiv / childCount; double h = this.BASE_HEIGHT * scale / maxDiv / childCount; double x = w * i + 50; double y = 20 ; ResourcePath res = resNode.getResourceIdentifier(); Object resource = graph.insertVertex(parent, null, res.toString(), x, y, w, h, "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); // insert a resource as a vertex resources.put(resNode, resource); i++; createNextChildSimulateResourceVerticies(graph, resource, resNode, resources); } } finally { graph.getModel().endUpdate(); } return graph; } private void createNextChildSimulateResourceVerticies(mxGraph graph, Object parent, Resource resNode, Map<Resource, Object> resources) { //sample Collection<Resource> children = resNode.getChildren(); if (children != null) { //List<Resource> children = resNode.getChildren(); double i = 1; double childCount = children.size(); for (Resource childNode: children) { Object childResource = setLayout(graph, parent, childNode.getResourceIdentifier(), i, childCount); resources.put(childNode, childResource); i++; createNextChildSimulateResourceVerticies(graph, childResource, childNode, resources); } } if (children == null || children.size() == 0) { Object state = graph.insertVertex(parent, null, resNode.getState().getValue().toString(), 0.5, 0.5, 0.25, 0.25, "opacity=0;verticalAlign=down;", true); // insert a state label as a vertex } } }