Newer
Older
AlgebraicDataflowArchitectureModel / AlgebraicDataflowArchitectureModel / src / application / simulator / SimulationLayout.java
@Shohei Yamagiwa Shohei Yamagiwa on 1 Dec 5 KB Format files
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.Map;

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
		}
	}
}