/******************************************************************************* * Copyright (c) 2006-2012 * Software Technology Group, Dresden University of Technology * DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026 * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Software Technology Group - TU Dresden, Germany; * DevBoost GmbH - Berlin, Germany * - initial API and implementation ******************************************************************************/ package org.reuseware.lacome.adjustment.arranger; import java.util.List; import java.util.Iterator; import org.reuseware.lacome.DiagramDescription; import org.reuseware.lacome.strategy.DiagramComparator; import org.reuseware.lacome.strategy.MultiSourceDiagramArranger; /** * This arranger moves diagrams uniformly outwards from a center point. * This approach is called <i>uniform scaling</i>. This arranger considers * all diagrams of one composition step together. */ public class UniformScalingArranger implements MultiSourceDiagramArranger { /** * @param contributingDiagrams diagrams with additional nodes * @param receivingDiagram extended diagram */ public void arrange(List<DiagramDescription> contributingDiagrams, DiagramDescription receivingDiagram) { fcdiArrange(contributingDiagrams); int counter = 1; //in some cases the algorithm has to run //several times. while (isOverlap(contributingDiagrams) && counter <= 10) { counter++; int centerx = findCenterX(contributingDiagrams); int centery = findCenterY(contributingDiagrams); scaleUnified(contributingDiagrams, centerx, centery); } } /** * This method arranges the source diagrams according to the x and y values given by the * composition program. This is the first step towards UnifiedScaling since the center point * for the approach can be computed after this. * * @param diagram given diagram that has to be moved */ private static void fcdiArrange(List<DiagramDescription> diagram) { Iterator<DiagramDescription> diagramIterator = diagram.iterator(); while (diagramIterator.hasNext()) { DiagramDescription diag = diagramIterator.next(); diag.getTargetBounds().setX(diag.getTargetBounds().getX()); diag.getTargetBounds().setY(diag.getTargetBounds().getY()); } } /** * This method computes the new x and y values for the diagrams according to UnifiedScaling. * This algorithm expands the diagram in all directions from a center point (x,y) using a * scale factor s. * * @param diagrams List of diagrams being the source diagrams the new values should be assigned to * @param centerx the x value for the center point * @param centery the y value for the center point */ private static void scaleUnified(List<DiagramDescription> diagrams, int centerx, int centery) { //(a+s(x-a),b+s(y-b)) int scaleFactor = 2; int oldx = 0; int oldy = 0; Iterator<DiagramDescription> fragit = diagrams.iterator(); while (fragit.hasNext()) { DiagramDescription diag = fragit.next(); oldx = diag.getTargetBounds().getX(); oldy = diag.getTargetBounds().getY(); diag.getTargetBounds().setX(centerx + scaleFactor * (oldx - centerx)); diag.getTargetBounds().setY(centery + scaleFactor * (oldy - centery)); } } /** * This method finds the x value of the center point. * * @param diagram list of diagrams being the source diagrams of a composition step * @return the x value of the center point */ private static int findCenterX(List<DiagramDescription> diagram) { Iterator<DiagramDescription> diagramIterator = diagram.iterator(); int x = 0; int x1 = 2000; while (diagramIterator.hasNext()) { DiagramDescription diag = diagramIterator.next(); //find the biggest x value, starting at x=0 if ((diag.getTargetBounds().getX() + diag.getSourceBounds().getWidth()) > x) { x = diag.getTargetBounds().getX() + diag.getSourceBounds().getWidth(); } //usually the first fragment does not start at x=0 //so you have to add the white space again for //a correct computation if (diag.getTargetBounds().getX() < x1) { x1 = diag.getTargetBounds().getX(); } } return (x1 + x) / 2; } /** * This method finds the y value of the center point. * * @param diagrams list of diagrams being the source diagrams of a composition step * @return the y value of the center point */ private static int findCenterY(List<DiagramDescription> diagrams) { Iterator<DiagramDescription> diagramIterator = diagrams.iterator(); int y = 0; int y1 = 2000; while (diagramIterator.hasNext()) { DiagramDescription diag = diagramIterator.next(); //find the biggest y value, starting at y=0 if ((diag.getTargetBounds().getY() + diag.getSourceBounds().getHeight()) > y) { y = diag.getTargetBounds().getY() + diag.getSourceBounds().getHeight(); } //usually the first fragment does not start at y=0 //so you have to add the white space again for //a correct computation if (diag.getTargetBounds().getY() < y1) { y1 = diag.getTargetBounds().getY(); } } return (y1 + y) / 2; } /** * This method performs the overlap check for the list of contributing fragments * involved in the composition. * * @param diagrams list of diagrams * @return true if two diagrams of the list overlap */ private static boolean isOverlap(List<DiagramDescription> diagrams) { Iterator<DiagramDescription> diagramIterator = diagrams.iterator(); boolean overlap = false; int actDiag = 0; //Fragments are already sorted by XYPositionComparator!! //from second contributing diagram (index=1) on //each one has to be compared to it's predecessors while (diagramIterator.hasNext()) { actDiag++; DiagramDescription source1 = diagramIterator.next(); for (int i = actDiag; i < diagrams.size(); i++) { DiagramDescription source2 = diagrams.get(i); int source1x1 = source1.getTargetBounds().getX() + source1.getSourceBounds().getWidth(); int source1y1 = source1.getTargetBounds().getY(); int source1y2 = source1y1 + source1.getSourceBounds().getHeight(); int source2x1 = source2.getTargetBounds().getX(); int source2y1 = source2.getTargetBounds().getY(); int source2y2 = source2y1 + source2.getSourceBounds().getHeight(); //only two options for overlaps because the //others are eliminated by the sorting if ((source1x1 > source2x1) && (source1y2 > source2y1) && (source2y2 > source1y1)) { overlap = true; } else { if ((source1x1 > source2x1) && (source1y1 > source2y1) && (source2y2 > source1y1)) { overlap = true; } } } } return overlap; } protected DiagramComparator comparator; /** * @return the current comparator used by this arranger */ public DiagramComparator getComparator() { return comparator; } /** * @param comparator the comparator for this arranger */ public void setComparator(DiagramComparator comparator) { this.comparator = comparator; } }