All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.gluebooster.java.booster.basic.math.GeometryBoostUtils Maven / Gradle / Ivy

Go to download

Basic classes to support the development of applications. There should be as few dependencies on other frameworks as possible.

The newest version!
package net.sf.gluebooster.java.booster.basic.math;

import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;

import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;

import edu.uci.ics.jung.algorithms.cluster.BicomponentClusterer;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.UndirectedGraph;
import edu.uci.ics.jung.graph.UndirectedSparseGraph;
import net.sf.gluebooster.java.booster.basic.container.Tuple;
import net.sf.gluebooster.java.booster.basic.gui.awt.BoostedRectangle;
import net.sf.gluebooster.java.booster.basic.gui.awt.ShapeComparator;
import net.sf.gluebooster.java.booster.basic.math.graph.GraphSequenceClusterer;
import net.sf.gluebooster.java.booster.basic.math.graph.JungGraphBoostUtils;
import net.sf.gluebooster.java.booster.basic.transformation.CallableDelegate;
import net.sf.gluebooster.java.booster.essentials.eventsCommands.Callable;
import net.sf.gluebooster.java.booster.essentials.logging.LogBooster;
import net.sf.gluebooster.java.booster.essentials.meta.objects.DisplayConfiguration;
import net.sf.gluebooster.java.booster.essentials.meta.objects.ObjectDescription;
import net.sf.gluebooster.java.booster.essentials.utils.ContainerBoostUtils;

/**
 * Geometric objects often are represented here as graphs. The vertices are shapes (example rectangle). Lines bewtween the vertices are edges
 * 
 * @author CBauer
 * @defaultParamText xTranslation translation along the x-axis
 * @defaultParamText yTranslation translation along the y-axis
 * @defaultParamText stopAfterFirstOverlapping should the computation be stopped after the first overlapping (true) or compute all overlappings (false)
 *
 */
public class GeometryBoostUtils {

	/**
	 * The logger
	 */
	private static LogBooster log = new LogBooster(GeometryBoostUtils.class);

	/**
	 * Should each step of computations be displayed. Used for debugging.
	 */
	private static boolean displayEachStep = false;

	/**
	 * Counter to create unique ids of placeholders
	 */
	private static int placeholderCounter = 0;

	/**
	 * Translates some objects
	 * 
	 * @param geometricObjects
	 *            the vertices are translated
	 * @param xTranslation
	 * @param yTranslation
	 */
	public static  void translate(
			Graph geometricObjects, int xTranslation,
			int yTranslation) {
		for (Object geometricObject : geometricObjects.getVertices()) {
			translate(geometricObject, xTranslation, yTranslation);
		}
	}

	/**
	 * Translates one object
	 * 
	 * @param geometricObject
	 *            this object will be translated
	 */
	public static void translate(Object geometricObject, int xTranslation,
			int yTranslation) {

		if (geometricObject instanceof Rectangle) {
			Rectangle rect = (Rectangle) geometricObject;
			setPosition(rect, rect.x + xTranslation, rect.y + yTranslation, 0);
		} else {
			throw new IllegalStateException(
					"geometric object not (yet) supported " + geometricObject);
		}
	}

	/**
	 * Sets the position of an object
	 * 
	 * @param geometricObject
	 *            will be repositioned
	 * @param x
	 *            the new x value
	 * @param y
	 *            the new y value
	 * @param translation
	 *            an additional translation to the x and y
	 */
	public static void setPosition(Object geometricObject, int x, int y,
			int translation) {
		if (geometricObject instanceof Rectangle) {
			Rectangle rect = (Rectangle) geometricObject;
			rect.x = translation + x;
			rect.y = translation + y;
		} else {
			throw new IllegalStateException(
					"geometric object not (yet) supported " + geometricObject);
		}
	}

	/**
	 * Repositions some objects so that they don't overlap
	 * 
	 * @param graph
	 *            the vertices are repositioned
	 * @param constraints
	 *            additional constraints
	 */
	public static  void repositionWithoutOverlapping(
			Graph graph,
			// Collection shapes,
			// MultiMap connectedShapes,
			GeometryPositionConstraint constraints) {
		boolean doDisplayEachStep = displayEachStep;
		if (doDisplayEachStep) {
			JungGraphBoostUtils.displayShapes(new DisplayConfiguration("Origin", graph));
			if (!GeometryBoostUtils.hasOverlappingVertices(graph, true)
					.isEmpty()) {
				log.info("Overlapping before repositioning "
						+ graph.getVertices().toString());
			}
		}

		if (repositionSpecialStructures(graph, constraints)) {
			return;
		}
		
		// TODO consider the constraints
		
		addMargin(graph, constraints.getMinimumDistance());

		if (doDisplayEachStep) {
			JungGraphBoostUtils.displayShapes(new DisplayConfiguration("added margin",
					graph));
		}

		repositionWithoutOverlappingByMovingUpOrRight(graph, constraints);
		//repositionWithoutOverlappingByMovingToTheRightAndUp(shapes,
		// minimumDistance);

		String afterStep = "";

		if (doDisplayEachStep) {
			afterStep = graph.getVertices().toString();
			JungGraphBoostUtils.displayShapes(new DisplayConfiguration(
					"after repositionWithoutOverlappingByMovingUp", graph));
			if (!GeometryBoostUtils.hasOverlappingVertices(graph, true)
					.isEmpty()) {
				log.info("Overlapping after repositioning " + afterStep);
			}
		}

		// repositionWithoutOverlappingWithEdges(shapes, connectedShapes);
		//
		// if (displayEachStep) {
		// Refactor.displayShapes(
		// "after repositionWithoutOverlappingWithEdges", shapes,
		// connectedShapes);
		// if (GeometryBoostUtils.isOverlapping(shapes)) {
		// log.info("Overlapping after repositionWithoutOverlappingWithEdges. Before: "
		// + afterStep + "\n after " + shapes.toString());
		// }
		// }

	}

	// TODO refactor before using
	// private static  void repositionWithoutOverlappingWithEdges(
	// Graph graph
	// // Collection shapes,
	// // MultiMap connectedShapes
	// ) {
	//
	// if (!GeometryBoostUtils.hasOverlappingVertices(graph, true).isEmpty()) {
	// log.info("shapes are already overlapping. Therefore nothing is done");
	// return;
	// }
	//
	// boolean didSomething = false;
	//
	// int margin = 10;
	//
	// /*
	// * // add edges with the opposite directions (so there are at least two
	// * // edges for each connection A-B, one from A to B, one from B to A)
	// * MultiHashMap edges = new MultiHashMap(connectedShapes);
	// * for (Entry entry : connectedShapes.entrySet()) {
	// * Collection collection = (Collection) entry .getValue(); for (Shape s : collection) { edges.put(s,
	// * entry.getKey()); } }
	// */
	//
	// int counter = 0;
	// // reposition one object then begin anew
	// do {
	// // Step 1
	// // Sort the shapes (vertices) so that the highest y,x is first
	// // (first
	// // sort by y then by x)
	// ArrayList ordered = new ArrayList(graph.getVertices());
	// Collections.sort(ordered, ShapeComparator.YX_COMPARATOR);
	// // lowest is first
	// Collections.reverse(ordered);
	// // now the highest is first
	// int size = ordered.size();
	//
	// for (int index = 0; index < size; index++) {
	//
	// Shape shape = ordered.get(index);
	// Rectangle bounds = shape.getBounds();
	// int minX = bounds.x;
	// int maxX = bounds.x + bounds.width;
	// int minY = bounds.y;
	// int maxY = bounds.y + bounds.height;
	//
	// int prefereredMovementUp = bounds.height + 10;
	// // use a margin additionally to the height.
	//
	// // Step A find overlappings with edges
	// // Overlappings can only occur with shapes that are higher up
	// // (before) or a least their upper end must be at least as high
	// // as
	// // the lower end of the shape.
	// // Handle at most one overlapping (stop if didSomething = true)
	// for (int j = 0; j < size && !didSomething; j++) {
	// if (j == index) {
	// continue; // do not compore the shape with itself
	// }
	//
	// Shape otherShape = ordered.get(j);
	//
	// Shape endpoint = isOverlappingWithEdgeOf(shape, otherShape,
	// edges);
	// // If there is an overlapping:
	// if (endpoint != null) {
	//
	// HashSet connectedComponents = new HashSet(
	// edges.get(shape));
	// while (connectedComponents.remove(shape)) {
	// // remove all connections with itself
	// }
	//
	// // has the shape a connected component that is lying
	// // more up (y is higher)
	// boolean hasUpper = false;
	// for (Shape connectedShape : connectedComponents) {
	// if (connectedShape.getBounds().y > bounds.y) {
	// hasUpper = true;
	// }
	// }
	//
	// // If the shape has no edge: move the shape up. If
	// // possible it's
	// // height (+ a margin); if it would overlap then even
	// // more up
	//
	// // If the shape has an edge to an upper other shape:
	// // move the shape
	// // up (if possible it's height (+ a margin))
	//
	// if (connectedComponents.isEmpty() || hasUpper) {
	// int up = getPossibleUpMovement(ordered, false,
	// shape, bounds.height + margin);
	// if (up > 0) {
	// translate(shape, 0, up);
	// didSomething = true;
	// if (!GeometryBoostUtils.hasOverlappingVertices(
	// graph,
	// true).isEmpty()) {
	// log.warn("shapes are overlapping after translation ");
	// translate(shape, 0, -up); // undo
	// // you may set a breakpoint here for
	// // analysis
	// getPossibleUpMovement(ordered, false,
	// shape, bounds.height + margin);
	//
	// }
	//
	// }
	// } else {
	//
	// // Else move the endpoints of the edge up. If
	// // possible
	// // the height of
	// // the shape (+ a margin)
	//
	// int up1 = getPossibleUpMovement(ordered, false,
	// otherShape, bounds.height + margin);
	//
	// int up2 = getPossibleUpMovement(ordered, false,
	// endpoint, bounds.height + margin);
	//
	// int up = Math.min(up1, up2);
	//
	// if (up > 0) {
	// translate(otherShape, 0, up);
	// translate(endpoint, 0, up);
	// didSomething = true;
	// if (!GeometryBoostUtils.hasOverlappingVertices(
	// graph, true).isEmpty()) {
	// log.warn("shapes are overlapping after translation ");
	// // undo
	// translate(otherShape, 0, -up);
	// translate(endpoint, 0, -up);
	//
	// // you may set a breakpoint here for
	// // analysis
	// getPossibleUpMovement(ordered, false,
	// otherShape, bounds.height + margin);
	// getPossibleUpMovement(ordered, false,
	// endpoint, bounds.height + margin);
	//
	// }
	//
	// }
	//
	// }
	// }
	// }
	// }
	// } while (didSomething && counter++ < 100);
	//
	// }

	/**
	 * Computes how much a shape can be moved up (y-axis) without intersecting other shapes
	 * 
	 * @param allShapesOrdered
	 *            all shapes
	 * @param orderedIncremental
	 *            are the shapes ordered incrementally (true) or decrementally (false)
	 * @param shapeToMoveUp
	 *            the shape to move up
	 * @param wantedMovementUp
	 *            the wanted distance to move
	 * @return the computed distance
	 */
	private static int getPossibleUpMovement(ArrayList allShapesOrdered,
			boolean orderedIncremental, Shape shapeToMoveUp,
			int wantedMovementUp) {
		int result = wantedMovementUp;

		Rectangle bounds = shapeToMoveUp.getBounds();
		Rectangle sweptArea = new Rectangle(bounds.x, bounds.y, bounds.width,
				bounds.height + wantedMovementUp);

		int start, end;
		if (orderedIncremental) {
			start = allShapesOrdered.indexOf(shapeToMoveUp) + 1;
			end = allShapesOrdered.size();
		} else {
			start = 0;
			end = allShapesOrdered.indexOf(shapeToMoveUp);
		}

		int margin = 5;
		for (int i = start; i < end; i++) {
			Shape shape = allShapesOrdered.get(i);
			Rectangle shapeBounds = shape.getBounds();
			if (shapeBounds.intersects(sweptArea)) {
				result = Math.min(result, shapeBounds.y
						- (bounds.y + bounds.height) - margin);
				// -5 is margin
				// shapeBounds----------
				// |
				// |
				// L shapeBounds.y -----
				// # margin
				// .
				// .
				// .result
				// .
				// .
				// bounds.y + bounds.height ----------
				// |
				// |
				// |
				// L bounds.y ------------------------

			}

		}

		if (result < 0) {
			result = 0;
		}

		return result;
	}

	/**
	 * Test whether a shape is overlapping with an edge
	 *
	 * @param graph
	 *            the graph with the edges and vertices
	 * @param positionOfEdge
	 *            SwingConstants TOP = MinX, MinY Center = Middle of shape
	 * @param shape
	 * @param edgeEndpoint
	 *            on edpoint of the edge
	 * @param connectedShapes
	 * @return the vertex, the edge and the endpoints of the edge
	 */
	public static  Collection, Void>> hasOverlappingVertexEdge(
			Graph graph, boolean stopAfterFirstOverlapping,
			int positionOfEdge
			/*
			, Shape shape,
			Shape edgeEndpoint,
			MultiMap connectedShapes*/) {

		HashSet, Void>> result = new HashSet, Void>>();
		
		for (Edge edge: graph.getEdges()){
			edu.uci.ics.jung.graph.util.Pair endpoints=   graph.getEndpoints(edge);
			Rectangle bounds1 = endpoints.getFirst().getBounds();
			Rectangle bounds2 = endpoints.getSecond().getBounds();
			Line2D.Double line = getLineBetween(endpoints.getFirst(),
					endpoints.getSecond(), positionOfEdge);
			if (SwingConstants.CENTER == positionOfEdge) {
				line = new Line2D.Double(bounds1.getCenterX(),
						bounds1.getCenterY(), bounds2.getCenterX(),
						bounds2.getCenterY());
			} else if (SwingConstants.TOP == positionOfEdge) {
				line = new Line2D.Double(bounds1.getMinX(), bounds1.getMinY(),
						bounds2.getMinX(), bounds2.getMinY());
			} else {
				throw new IllegalArgumentException(
						"position not supported, only SwingConstants.TOP and CENTER: "
								+ positionOfEdge);
			}

			for (Shape vertex : graph.getVertices()) {
				if (vertex != endpoints.getFirst()
						&& vertex != endpoints.getSecond()
						&& line.intersects(vertex.getBounds())) {
					result.add(Tuple.triple(vertex, edge, graph.getEndpoints(edge)));
					if (stopAfterFirstOverlapping) {
						return result;
					}
				}
			}
			
		}

		return result;
		
	}


	/**
	 * Computes the line between two shapes
	 * 
	 * @param shape1
	 *            the first shape
	 * @param shape2
	 *            the second shape
	 * @param positionOfEdge
	 *            where should the edge start/end (SwingConstants)
	 * @return the computed line
	 */
	private static Line2D.Double getLineBetween(Shape shape1, Shape shape2,
			int positionOfEdge) {
		Rectangle bounds1 = shape1.getBounds();
		Rectangle bounds2 = shape2.getBounds();
		Line2D.Double line;
		if (SwingConstants.CENTER == positionOfEdge) {
			line = new Line2D.Double(bounds1.getCenterX(),
					bounds1.getCenterY(), bounds2.getCenterX(),
					bounds2.getCenterY());
		} else if (SwingConstants.TOP == positionOfEdge) {
			line = new Line2D.Double(bounds1.getMinX(), bounds1.getMinY(),
					bounds2.getMinX(), bounds2.getMinY());
		} else {
			throw new IllegalArgumentException(
					"position not supported, only SwingConstants.TOP and CENTER: "
							+ positionOfEdge);
		}

		return line;
	}

	/**
	 * Has the graph overlapping edges
	 * 
	 * @param graph
	 *            the graph which edges are to be inspected
	 * @param stopAfterFirstOverlapping
	 *            should the algorithm stop after finding the first overlapping
	 * @param positionOfEdge
	 *            where should the edge start/end (SwingConstants)
	 * @return overlapping edges
	 */
	public static  Collection> hasOverlappingEdges(
			Graph graph, boolean stopAfterFirstOverlapping,
			int positionOfEdge) {

		HashSet> result = new HashSet>();

		for (Edge edge : graph.getEdges()) {
			edu.uci.ics.jung.graph.util.Pair endpoints = graph
					.getEndpoints(edge);
			Line2D.Double line = getLineBetween(endpoints.getFirst(),
					endpoints.getSecond(), positionOfEdge);
			if (endpoints.getFirst() != endpoints.getSecond()) {
				for (Edge edge2 : graph.getEdges()) {
					edu.uci.ics.jung.graph.util.Pair endpoints2 = graph
							.getEndpoints(edge2);
					if (!(endpoints.getFirst() == endpoints2.getFirst()
							|| endpoints.getFirst() == endpoints2.getSecond()
							|| endpoints.getSecond() == endpoints2.getFirst() || endpoints
								.getSecond() == endpoints2.getSecond())) {
						Line2D.Double line2 = getLineBetween(
								endpoints2.getFirst(), endpoints2.getSecond(),
								positionOfEdge);
						if (line.intersectsLine(line2)) {
							result.add(new MutablePair(edge, edge2));
							if (stopAfterFirstOverlapping) {
								return result;
							}
						}
					}
				}
			}
		}
		return result;
	}

	/**
	 * Move all shapes a margin to the right and up, so that no shape has x=0 or y = 0
	 * 
	 * @param graph
	 *            the graph to inspect
	 * @param margin
	 *            the new margin of the shapes
	 */
	private static  void addMargin(Graph graph,
			int margin) {

		//
		//
		for (Shape shape : graph.getVertices()) {
			translate(shape, margin, margin);
		}

		if (displayEachStep) {
			JungGraphBoostUtils.displayShapes(new DisplayConfiguration("After Step 0",
					graph));
		}

	}

	/**
	 * Repositions shapes by moving them up or right, so that they no longer overlap
	 * 
	 * @param graph
	 *            contains the shapes
	 * @param constraints
	 *            additional constraints
	 */
	private static  void repositionWithoutOverlappingByMovingUpOrRight(
			Graph graph,
			GeometryPositionConstraint constraints) {

		int minimumDistance = constraints.getMinimumDistance();
		// Step 1
		// first sort the collection according to the position
		// lowest y is first, equal y means lowest x is first
		ArrayList ordered = new ArrayList(graph.getVertices());
		Collections.sort(ordered, ShapeComparator.YX_COMPARATOR);
		int size = ordered.size();

		// Step 2
		// then remove overlapping by moving the remaining shapes to the right
		// and up
		for (int index = 0; index < size; index++) {
			Shape shape = ordered.get(index);
			Rectangle bounds = shape.getBounds();
			int minY = bounds.y;
			int maxY = bounds.y + bounds.height;

			for (int j = index + 1; j < size; j++) {
				Shape shape2 = ordered.get(j);
				Rectangle bounds2 = shape2.getBounds();
				int minY2 = bounds2.y;

				if (bounds2.intersects(bounds)) {

					for (int k = j; k < size; k++) {
						Shape shape3 = ordered.get(k);
						Rectangle bounds3 = shape3.getBounds();
						int translateX = 0;
						int translateY = 0;

						if (bounds3.y == bounds.y) {
							// move to the right
							translateX = bounds.width + minimumDistance;
						} else {
							// move up
							translateY = bounds.height + minimumDistance;
						}

						translate(shape3, translateX, translateY);
					}
				}
			}
		}

		if (displayEachStep) {
			JungGraphBoostUtils.displayShapes(new DisplayConfiguration("End", graph));
		}

	}

	/**
	 * Are some shapes overlapping?
	 * 
	 * @param graph
	 *            contains the shapes
	 * @return overlapping shapes
	 */
	public static  Collection> hasOverlappingVertices(
			Graph graph,
			boolean stopAfterFirstOverlapping) {

		HashSet> result = new HashSet>();

		ArrayList shapeslist = new ArrayList(graph.getVertices());

		int size = shapeslist.size();
		for (int i = 0; i < size; i++) {
			Shape shape = shapeslist.get(i);
			for (int j = i + 1; j < size; j++) {
				Shape shape2 = shapeslist.get(j);

				if (shape.intersects(shape2.getBounds())) {
					result.add(new MutablePair(shape, shape2));
					if (stopAfterFirstOverlapping) {
						return result;
					}
				}
			}
		}

		return result;
	}

	/**
	 * Are there overlappings in some shapes and lines
	 * 
	 * @param graph
	 *            contains the shapes (vertices) and lines (edges).
	 * @return [overlapping vertices (shapes), overlapping between vertex and edge, overlapping edges]
	 */
	public static  Tuple>, Collection, Void>>, Collection>, Void> hasOverlappings(
			Graph graph,
			boolean stopAfterFirstOverlapping) {

		Tuple>, Collection, Void>>, Collection>, Void> result = new Tuple>, Collection, Void>>, Collection>, Void>();
		result.setThird(Collections.EMPTY_SET);
		result.setSecond(Collections.EMPTY_SET);
	
		result.setFirst(hasOverlappingVertices(graph, stopAfterFirstOverlapping));
		if (stopAfterFirstOverlapping && !result.getFirst().isEmpty()) {
			return result;
		}
		
		result.setSecond(hasOverlappingVertexEdge(graph,
				stopAfterFirstOverlapping, SwingUtilities.TOP));
		if (stopAfterFirstOverlapping && !result.getSecond().isEmpty()) {
			return result;
		}

		result.setThird(hasOverlappingEdges(graph, stopAfterFirstOverlapping,
				SwingUtilities.TOP));
		// if (stopAfterFirstOverlapping && !result.getThird().isEmpty()) {
		// return result;
		// }

		return result;

	}

	/**
	 * Computes the dimension of the layout of the graph
	 * 
	 * @param graphs
	 *            multiple graphs that are inspected
	 * @return the rectangle that covers all graphs
	 */
	public static Rectangle getGraphDimension(
			Collection> graphs) {
		Collection shapes = new ArrayList();
		for (Graph graph : graphs) {
			shapes.addAll(graph.getVertices());
		}
		return getDimension(shapes);

	}

	/**
	 * Computes the dimension of the layout of the graph
	 * 
	 * @param graphs
	 *            multiple graphs that are inspected
	 * @return the rectangle that covers all graphs
	 */
	public static Rectangle getDimension(Graph... graphs) {
		Collection shapes = new ArrayList();
		for (Graph graph : graphs) {
			shapes.addAll(graph.getVertices());
		}
		return getDimension(shapes);

	}

	/**
	 * Return the rectangle in which all the shapes lie.
	 * 
	 * @param shapes
	 *            the inspected shapes
	 * @return the covering rectangle
	 */
	public static Rectangle getDimension(Collection shapes) {

		if (shapes == null || shapes.isEmpty()) {
			return new Rectangle(0, 0, 0, 0);
		}
		// Algorithm get the highest x and and the highest height
		// The algorithm can be improved.
		int minX = Integer.MAX_VALUE;
		int minY = Integer.MAX_VALUE;
		int maxX = Integer.MIN_VALUE;
		int maxY = Integer.MIN_VALUE;

		for (Shape shape : shapes) {
			Rectangle bounds = shape.getBounds();
			// Currently it is supposed, that the width and heigt is positive
			minX = Math.min(minX, bounds.x);
			minY = Math.min(minY, bounds.y);
			maxX = Math.max(maxX, bounds.x + bounds.width);
			maxY = Math.max(maxY, bounds.y + bounds.height);
		}

		return new Rectangle(minX, minY, maxX - minX, maxY - minY);
	}

	/**
	 * Return the bounds of shapes and the maximum of the heights and widths
	 *
	 * @param shapes
	 *            the inspected shapes
	 * @return [ List of rectangle of each shape, dimension off all shapes together
	 */
	public static Pair, Dimension> getEachBounds(List shapes) {
		int maxWidth = 0, maxHeight = 0;
		int size = shapes.size();
		List boundsList = new ArrayList(size);
		for (int i = 0; i < size; i++) {
			Rectangle bounds = shapes.get(i).getBounds();
			boundsList.add(bounds);
			maxWidth = Math.max(maxWidth, bounds.width);
			maxHeight = Math.max(maxHeight, bounds.height);
		}

		return new MutablePair, Dimension>(boundsList,
				new Dimension(maxWidth, maxHeight));
	}


	/**
	 * Layouts a sequence of nodes
	 * 
	 * @param graph
	 *            contains the shapes
	 * @param constraints
	 *            additional constraints
	 * @return true if the graph is a sequence and the layout was successful
	 */
	private static boolean positionSequence(Graph graph,
			GeometryPositionConstraint constraints) {

		boolean checkAfterwards = true;

		// default value
		if (constraints == null) {
			constraints = new GeometryPositionConstraint();
		}

		int minimumDistance = constraints.getMinimumDistance();



		GraphSequenceClusterer sequenceClusterer = new GraphSequenceClusterer();
		Set> sequences = sequenceClusterer
				.transform((UndirectedGraph) JungGraphBoostUtils
						.createUndirectedGraph(graph));

		// if the whole graph is no sequence
		if (sequences.isEmpty()) {
			return false;
		} else {
			List sequence = new ArrayList(sequences.iterator()
					.next());

			if (sequence.size() != graph.getVertexCount()) {
		
				// if the sequence is not the whole graph
				return false;
				// TODO divide and conquer
			} else {
				// one sequence
				 
				// make a row
				List ordered = sequenceClusterer
						.order(sequence, graph, true);
	
				log.info("todo: try to find a quadratic layout, to minimize width and height");
	
				// determine whether horizontal or vertical
	
				// if there are edges to higher or lower y prefer horizontal
				HashSet horizontal = new HashSet(
						constraints.getEdgesToHigherY());
				horizontal.addAll(constraints.getEdgesToLowerY());
	
				// if there are edges to higher or lower x prefer vertical
				HashSet vertical = new HashSet(
						constraints.getEdgesToHigherX());
				vertical.addAll(constraints.getEdgesToLowerX());
	
				// prefer the direction with more elements
				boolean displayVertical = vertical.size() > horizontal.size();
	
				Rectangle bounds = constraints.getBounds();
				if (bounds == null) {
					bounds = new Rectangle(minimumDistance, minimumDistance,
							Integer.MAX_VALUE, Integer.MAX_VALUE);
				}

				int x = bounds.x;
				int y = bounds.y;

				Pair, Dimension> boundsPair = getEachBounds(sequence);
				int maxWidth = Math.min(boundsPair.getRight().width
						+ minimumDistance, bounds.width);
				int maxHeight = Math.min(boundsPair.getRight().height
						+ minimumDistance, bounds.height);

				for (Shape s : ordered) {
					int xOffset = 0;
					int yOffset = 0;
					if (displayVertical) {
						y += minimumDistance;
						if (constraints.hasEdgeToHigherX(s)) {
							xOffset = maxWidth;
							// because the edge may otherwise intersect the other
							// elements of the sequence

							// TODO it would be better if the offset is computed
							// dynamically considering the width of s
						}
	
					} else { // horizontal
						x += minimumDistance;
						if (constraints.hasEdgeToHigherY(s)) {
							yOffset = maxHeight;
							// because the edge may otherwise intersect the other
							// elements of the sequence

							// TODO it would be better if the offset is computed
							// dynamically considering the height of s
						}
					}
	
					setPosition(s, x + xOffset, y + yOffset, 0);
					if (displayVertical) {
						y += s.getBounds().height;
					} else {
						x += s.getBounds().width;
					}
	
				}

				if (checkAfterwards) {
					constraints.check(graph, false);
				}

				return true;
			}
		}
	}

	/**
	 * Algorithms to reposition special structurs. The repositioning tries to avoid overlappings.
	 * 
	 * @param graph
	 *            contains the shapes
	 * @param constraints
	 *            constraints of the shapes
	 * @return true, if the repositioning was successful
	 */
	public static boolean repositionSpecialStructures(Graph graph,
			GeometryPositionConstraint constraints) {

		int minimumDistance = constraints.getMinimumDistance();

		int size = graph.getVertices().size();

		// put the shapes and their bounds in arrays
		// and compute the maxiumul height and width of one shape

		Shape[] shape = new Shape[size];
		shape = graph.getVertices().toArray(shape);
		List shapeList = Arrays.asList(shape);



		// Variant 0: try if graph is one sequence.
		if (positionSequence(graph, constraints)) {
				return true;
		}

		Pair, Dimension> boundsPair = getEachBounds(shapeList);
		List boundsList = boundsPair.getKey();

		// Variant 1: otherwise

		// Step 1: reposition without constraints.bounds
		switch (size) {
		case 0:
		case 1:
			// nothing needs to be done
			break;
		case 2: // horizontal line ordering depends which element has an edge to
				// the left

			// index of shapes
			int left = 0;
			int right = 1;
			if (constraints != null
					&& (constraints.getEdgesToHigherX().contains(shape[0]) || constraints
							.getEdgesToLowerX().contains(shape[1]))) {
				left = 1;
				right = 0;
			}
			;
			
			setPosition(shape[left], 0, 0, minimumDistance);
			setPosition(shape[right], boundsList.get(left).width
					+ minimumDistance, 0,
					minimumDistance);
			break;
		case 3:
		case 4:
		case 5:
			Point2D[] positions = createDefaultShape(shapeList, boundsList,
					constraints, graph);
			for (int i = 0; i < shape.length; i++) {
				setPosition(shape[i], (int) positions[i].getX(),
						(int) positions[i].getY(), 0);
			}
			break;
		default:
			return false;
		}

		// Step 2: consider bounds
		if (constraints != null && constraints.getBounds() != null) {
			Rectangle dim = getDimension(graph.getVertices());
			Rectangle constraintBounds = constraints.getBounds();

			if (dim.width > constraintBounds.width
					|| dim.height > constraintBounds.height) {
				
				scale(graph, dim.getLocation(), new Point2D.Double(
Math.min(
								((double) constraintBounds.width)
										/ (double) dim.width, 1), Math
								.min(((double) constraintBounds.height)
										/ (double) dim.height, 1)), false);
				dim = getDimension(graph.getVertices());//update
			}

			translate(graph, -dim.x + constraintBounds.x, -dim.y
					+ constraintBounds.y);
			return true;

		} else {
			return true; // all ok
		}
	}

	/**
	 * Positions some shapes (with as few overlappings as possible)
	 * 
	 * @param graph
	 *            contains the shapes
	 * @param constraints
	 *            additional constraints
	 * @return true if successful
	 */
	public static  boolean position(Graph graph,
			GeometryPositionConstraint constraints) throws Exception {

		boolean result;
		if (repositionSpecialStructures(graph, constraints)) {
			result = true;
		} else {
			result = positionByDivideAndConquer(graph, constraints);
		}

		constraints.check(graph, false);
		checkOverlappings(graph, ObjectDescription.createFlag(true, false), true, true, false,
				constraints);



		return result;

	}

	/**
	 * Positions some shape by using a divide and conquer algorithm.
	 * 
	 * @param graph
	 *            contains the shapes
	 * @param constraints
	 *            additional constraints
	 * @return true, if solved
	 */
	public static  boolean positionByDivideAndConquer(
			Graph graph,
			GeometryPositionConstraint constraints) throws Exception {

		int minimumDistance = constraints.getMinimumDistance();

		UndirectedSparseGraph undirectedGraph = JungGraphBoostUtils
				.createUndirectedGraph(graph);
		int graphSize = undirectedGraph.getVertexCount();

		// clusterer to divide the graph into components
		ArrayList, Set>>> clusterers = new ArrayList, Set>>>();
		clusterers.add(new GraphSequenceClusterer());
		clusterers.add(new CallableDelegate(new BicomponentClusterer()));

		for (Callable, Set>> clusterer : clusterers) {
			Set> components = clusterer.call(undirectedGraph);

			// only if it is a real subgraph
			Set set1 = ContainerBoostUtils.getOneOf(components);
			if (set1 != null && set1.size() != graphSize) {
				// to avoid set problems create a duplicate
				set1 = new HashSet(set1);
				// set1 will be one inner component of the remaining graph

				// split the graph in the graph of set1, the remaining graph and
				// the edges between the graphs
				Tuple, UndirectedGraph, List>, Void> separation = JungGraphBoostUtils
						.split(graph, set1);

				// do a first layout of graph1/set1 to get a feeling of the
				// necessary dimensions
				UndirectedGraph graph1 = separation.getFirst();
				position(graph1, constraints);
				Rectangle set1Dim = getDimension(set1);

				List> connectionsBetween = separation
						.getThird();
				boolean graphsAreConnected = !connectionsBetween.isEmpty();
				// the placeholder for the graph set1 within set2 if necessary
				Rectangle placeholder = new BoostedRectangle("placeholder"
						+ placeholderCounter++);

				UndirectedGraph graph2 = separation.getSecond();

				if (graphsAreConnected) {
					// add the placeholder of graph1 and its connections

					// first modify the coordinates, because later modified
					// vertices are no longer found in the graph
					placeholder.x = 0;
					placeholder.y = 0;

					Pair, Dimension> boundsPair = getEachBounds(new ArrayList(
							set1));
					// add some extra space because the graph1 will be layouted
					// again later with more constraints
					// use the maxiumum of the dimensions because the second
					// layout
					// may interchange x with y
					// add some extra width, because the second layout may be
					// larger
					int set1DimMax = Math.max(set1Dim.width, set1Dim.height);
					placeholder.width = set1DimMax + 2
							* boundsPair.getRight().width + minimumDistance;
					placeholder.height = set1DimMax + 2
							* boundsPair.getRight().height + minimumDistance;

					graph2.addVertex(placeholder);
					// add the edges to the placeholder
					for (Tuple connection1to2 : connectionsBetween) {
						graph2.addEdge(connection1to2.getFirst(), placeholder,
								connection1to2.getThird());
					}
				}

				// now do a layout of the remaining graph with the placeholder
				position(graph2, constraints);
				Rectangle graph2Dim = getDimension(graph2.getVertices());
				if (constraints.isDisplayPartResults()) {
					JungGraphBoostUtils.displayShapes(new DisplayConfiguration(
							"surrounding graph", null, new Rectangle(0, 0, 400,
									400), graph2));
				}

				Point newLocationOfSet1;
				Dimension translationOfSet1;
				if (graphsAreConnected) {
					// translate to the position of the placeholder
					newLocationOfSet1 = placeholder.getLocation();
					Rectangle placeholderBounds = placeholder.getBounds();

					// do a new layout of graph1/set1; now with the constraints
					// of the surrounding graph 2

					GeometryPositionConstraint graph1Constraints = new GeometryPositionConstraint(
							new ArrayList(), new ArrayList(),
							new ArrayList(), new ArrayList(),
							null);
					graph1Constraints.setMinimumDistance(constraints
							.getMinimumDistance());

					Rectangle graph1Bounds = placeholder.getBounds();
					graph1Constraints.setBounds(graph1Bounds);
					for (Tuple conn : connectionsBetween) {
						Shape graph1Vertex = conn.getSecond();
						Shape graph2Vertex = conn.getThird();
						Rectangle graph2VertexPosition = graph2Vertex
								.getBounds();

						graph1Constraints.addEdgesToLowerHigher(
								graph2VertexPosition, placeholderBounds,
								graph1Vertex);

					}

					position(graph1, graph1Constraints);
					if (constraints.isDisplayPartResults()) {
						JungGraphBoostUtils.displayShapes(new DisplayConfiguration(
								"inner graph 1", graph1));
					}

					if (!checkOverlappings(graph, ObjectDescription.createFlag(false, false), true,
							true, false, constraints)) {
						// do the checking and position again for debugging
						// purposes.
						Rectangle preferred = new Rectangle(0, 0, 500, 500);
						JungGraphBoostUtils.displayShapes(new DisplayConfiguration(
								"surrounding + inner graph ", null, preferred,
								graph, graph2, graph1));

						checkOverlappings(graph, ObjectDescription.createFlag(false, false), true,
								true, false, constraints);
						graph1Constraints.setDisplayPartResults(true);
						position(graph1, graph1Constraints);
						JungGraphBoostUtils.displayShapes(new DisplayConfiguration(
								"after positioned again", new Point(
										(int) preferred.getWidth(), 0), null,
								graph));

					}

				} else {
					// just to the right
					newLocationOfSet1 = new Point(graph2Dim.x + graph2Dim.width
							+ minimumDistance, minimumDistance);

					translate(set1Dim, newLocationOfSet1, set1);

					if (!checkOverlappings(graph, ObjectDescription.createFlag(false, false), true,
							true, false, constraints)) {
						JungGraphBoostUtils.displayShapes(new DisplayConfiguration(
								"overlapping in graph", graph));
						log.debug("created overlappings");
					}

				}

				return true;


			}
		}
		
		// if no subcomponent to divide has been found
		// just try to remove overlappings
		repositionWithoutOverlapping(undirectedGraph, constraints);
		return false;

	}

	/**
	 * Computes the translation of a rectangle so that its location ist at a new location.
	 * 
	 * @param translateThisRectangle
	 *            the rectangle to translate
	 * @param location
	 *            the new location
	 * @param shapesToTranslate
	 *            the shapes are translated
	 * @return the translation
	 */
	private static Dimension translate(Rectangle translateThisRectangle,
			Point location, Collection shapesToTranslate) {

		Dimension translation = new Dimension(location.x
				- translateThisRectangle.x, location.y
				- translateThisRectangle.y);

		for (Shape shape : shapesToTranslate) {
			translate(shape, translation.width, translation.height);
		}
		return translation;

	}

	/**
	 * Creates a default shape for some corners.
	 * 
	 * @param corner
	 *            the objects to position in the corners. 1 := corner[1] 2:=corner[2], ...
	 * @param bounds
	 *            the bounds of the corner objects
	 * @param constraints
	 *            additional constraints
	 * @param graph
	 *            contains the corners
	 * @return the points of the corresponding corners
	 */
	public static  Point2D[] createDefaultShape(List corner,
			List bounds,
			GeometryPositionConstraint constraints,
			Graph graph) {

		int size = corner.size();
		if (size == 3) {
			return createTriangle(corner, bounds, constraints);
		} else if (size == 4) {
			return createQuadrangle(corner, bounds, constraints);
		} else if (size == 5) {
			return createPentagon(corner, bounds, constraints, graph);
		} else {
			throw new IllegalArgumentException("size not yet supported " + size);
		}

	}

	/**
	 * Creates a quandrangle
	 * 
	 * @param corner
	 *            the 4 corners
	 * @param bounds
	 *            the bounds of the corresponding corners
	 * @param constraints
	 *            additional constraints
	 * @return the points of the coresponding corners.
	 */
	public static  Point2D[] createQuadrangle(List corner,
			List bounds,
			GeometryPositionConstraint constraints) {

		int size = 4;

		Point2D[] result = new Point2D[size];

		int dist = constraints.getMinimumDistance();

		int maxWidth = 0, maxHeight = 0;
		for (int i = 0; i < size; i++) {
			maxWidth = Math.max(maxWidth, bounds.get(i).width);
			maxHeight = Math.max(maxHeight, bounds.get(i).height);
		}

		// make a quardangle of the form
		// .0..
		// 1...
		// ...2
		// ..3.
		int index0 = -1;
		int index1 = -1;
		int index2 = -1;
		int index3 = -1;

		ArrayList top = new ArrayList(
				constraints.getObjectsWithEdgesToLowerYButNotHigherY());
		ArrayList bottom = new ArrayList(
				constraints.getObjectsWithEdgesToHigherYButNotLowerY());
		ArrayList left = new ArrayList(
				constraints.getObjectsWithEdgesToLowerXButNotHigherX());
		ArrayList right = new ArrayList(
				constraints.getObjectsWithEdgesToHigherXButNotLowerX());

		if (top.size() == 1) {
			Corner oneCorner = top.get(0);
			index0 = corner.indexOf(oneCorner);
		} else if (top.size() == 2) {
			Corner oneCorner = top.get(0);
			Corner twoCorner = top.get(1);
			if (right.contains(oneCorner)) {
				index0 = corner.indexOf(oneCorner);
				index1 = corner.indexOf(twoCorner);
			} else {
				index0 = corner.indexOf(twoCorner);
				index1 = corner.indexOf(oneCorner);

			}
		} else if (top.size() == 3) {
			Corner oneCorner = top.get(0);
			Corner twoCorner = top.get(1);
			Corner threeCorner = top.get(2);
			index0 = corner.indexOf(twoCorner);// the middle
			index1 = corner.indexOf(oneCorner);
			index2 = corner.indexOf(threeCorner);
		}

		ArrayList remaining = new ArrayList(Arrays.asList(0,
				1, 2, 3));
		remaining.removeAll(Arrays.asList(index0, index1, index2, index3));

		// fill in remaining indices
		if (index0 == -1) {
			index0 = remaining.remove(0);
		}
		if (index1 == -1) {
			index1 = remaining.remove(0);
		}
		if (index2 == -1) {
			index2 = remaining.remove(0);
		}
		if (index3 == -1) {
			index3 = remaining.remove(0);
		}

		// make a square with maxWidht and maxHeight distance between
		// the elements to avoid overlapping of edges with shapes
		// the square is a 3x3 Matrix with the shapes at the corners.
		// Each element has widht = maxWidth, height = maxHeight

		result[index0] = new Point2D.Double(dist + bounds.get(index1).width
				+ dist, dist);
		result[index1] = new Point2D.Double(dist, dist
				+ bounds.get(index0).height + dist);
		result[index2] = new Point2D.Double(dist + bounds.get(index1).width
				+ dist + bounds.get(index0).width + dist
				+ bounds.get(index3).width + dist, dist
				+ bounds.get(index0).height + dist + bounds.get(index1).height
				+ dist);
		result[index3] = new Point2D.Double(dist + bounds.get(index1).width
				+ dist + bounds.get(index0).width + dist, dist
				+ bounds.get(index0).height + dist + bounds.get(index1).height
				+ dist + bounds.get(index2).height + dist);

		return result;
	}
	
	/**
	 * Creates a triangle
	 * 
	 * @param corner
	 *            the objects to position in the corners. 1 := corner[1] 2:=corner[2], ...
	 * @param bounds
	 *            the bounds of the corner objects
	 * @param constraints
	 *            additional constraints
	 * @return the points of the corresponding corners
	 */
	public static  Point2D[] createTriangle(List corner,
			List bounds,
			GeometryPositionConstraint constraints) {

		Point2D[] result = new Point2D[3];
		int dist = constraints.getMinimumDistance();

		List top = constraints
				.getObjectsWithEdgesToLowerYButNotHigherY();
		if (top.size() == 2) {
			// the list is ordered from left to right
			// make triangle
			// ..left...........right
			// .......remaining......

			// TODO better consider additionally if left or right have edges to
			// the right or left

			int leftIndex = corner.indexOf(top.get(0));
			int rightIndex = corner.indexOf(top.get(1));

			ArrayList remaining = new ArrayList(
					Arrays.asList(0, 1, 2));
			remaining.removeAll(Arrays.asList(leftIndex, rightIndex));
			if (remaining.size() != 1) {
				throw new IllegalStateException("bug in code");
			}

			int downIndex = remaining.get(0);

			result[leftIndex] = new Point2D.Double(dist, dist);
			result[rightIndex] = new Point2D.Double(dist
					+ bounds.get(leftIndex).width + dist
					+ bounds.get(downIndex).width + dist, dist);
			result[downIndex] = new Point2D.Double(dist
					+ bounds.get(leftIndex).width + dist, dist
					+ Math.max(bounds.get(leftIndex).height,
							bounds.get(rightIndex).height) + dist);


		} else {
			// TODO other variants
			log.info("other variants missing");

			// Default Triangle
			// .1.
			// 2..
			// ..3
			Point2D point1, point2, point3;
			point1 = new Point2D.Double(dist + bounds.get(2).width + dist, dist);
			point2 = new Point2D.Double(dist, dist + bounds.get(1).height
					+ dist);
			point3 = new Point2D.Double(dist + bounds.get(2).width + dist
					+ bounds.get(1).width + dist, dist + bounds.get(1).height
					+ dist + bounds.get(2).height + dist);

			result[0] = point1;
			result[1] = point2;
			result[2] = point3;
		}

		return result;
		// setPosition(shape[oneIndex], 0, 0, minimumDistance);
		// setPosition(shape[twoIndex], bounds[0].width + minimumDistance,
		// 0,
		// minimumDistance);
		// setPosition(shape[threeIndex], bounds[0].width,
		// Math.max(bounds[0].height, bounds[1].height)
		// + minimumDistance, minimumDistance);
		// break;

	}

	/**
	 * Does scaling of the vertices of a graph
	 * 
	 * @param graph
	 *            contains the vertices to scale
	 * @param origin
	 *            the origin of the scaling
	 * @param scale
	 *            the multiplicand
	 * @param scaleVertexSize
	 *            should the size of the vertices scale, too
	 * 
	 */
	public static void scale(Graph graph, Point origin,
			Point2D scale, boolean scaleVertexSize) {

		if (scaleVertexSize) {
			log.debug("scale vertex size not yet supported");
		}

		for (Shape shape : graph.getVertices()) {
			Rectangle bounds = shape.getBounds();
			double newX = origin.x + ((double) bounds.x - origin.x)
					* scale.getX();
			double newY = origin.y + ((double) bounds.y - origin.y)
					* scale.getY();
			setPosition(shape, (int) newX, (int) newY, 0);
		}

	}

	/**
	 * Creates a pentagon.
	 * 
	 * @param corner
	 *            the 5 corners
	 * @param bounds
	 *            the bounds of the corresponding corners
	 * @param constraints
	 *            additional constraints
	 * @param graph
	 *            graph with the edges between the corners
	 * @return the points of the corners
	 */
	public static  Point2D[] createPentagon(List corner,
			List bounds,
			GeometryPositionConstraint constraints,
			Graph graph) {

		int size = 5;


		int dist = constraints.getMinimumDistance();

		int maxWidth = 0, maxHeight = 0;
		for (int i = 0; i < size; i++) {
			maxWidth = Math.max(maxWidth, bounds.get(i).width);
			maxHeight = Math.max(maxHeight, bounds.get(i).height);
		}
		//Pentagon
		// ..0......
		// .......4..
		//.1......
		// ......3...
		// ....2

		MultiValuedMap cornerPositions = new HashSetValuedHashMap<>();
		
		for (Corner vertex : corner) {
			cornerPositions.put(vertex, 0);
			cornerPositions.put(vertex, 1);
			cornerPositions.put(vertex, 2);
			cornerPositions.put(vertex, 3);
			cornerPositions.put(vertex, 4);
		}
		
		if (constraints != null){
			//remove unwanted positions
			for (Corner vertex: constraints.getEdgesToLowerY()){
				cornerPositions.get(vertex).remove(2);
				cornerPositions.get(vertex).remove(3);
			}
			for (Corner vertex: constraints.getEdgesToHigherY()){
				cornerPositions.get(vertex).remove(0);
			}
			for (Corner vertex: constraints.getEdgesToLowerX()){
				cornerPositions.get(vertex).remove(3);
				cornerPositions.get(vertex).remove(4);
			}
			for (Corner vertex: constraints.getEdgesToHigherX()){
				cornerPositions.get(vertex).remove(1);
			}
		}
		
		boolean doContinue = true;
		while (doContinue) {

			// if one corner has only one possible position then remove that
			// position from the others
			for (Corner vertex : corner) {
				if (cornerPositions.get(vertex).size() == 1) {
					Integer position = cornerPositions.get(vertex).iterator()
							.next();
					for (Corner otherVertex : corner) {
						if (otherVertex != vertex) {
							cornerPositions.get(otherVertex).remove(position);
						}
					}
				}
			}

			doContinue = false;
			// if one corner has preferred opportunities use one
			for (Corner vertex : corner) {
				Collection positions = cornerPositions.get(vertex);
				Integer position = null;
				if (positions.size() > 1) {
					if (positions.contains(0) && constraints.getEdgesToLowerY().contains(vertex)){
						position = 0;
					} else if (positions.contains(1) && constraints.getEdgesToLowerX().contains(vertex)){
							position = 1;
					} else if (positions.contains(2) && constraints.getEdgesToHigherY().contains(vertex)){
						position = 2;
					} else if (positions.contains(3) && constraints.getEdgesToHigherX().contains(vertex)){
						position = 3;
					} else if (positions.contains(4) && constraints.getEdgesToHigherX().contains(vertex)){
						position = 4;
					} else {
						// position = positions.iterator().next();
					}
					
					if (position != null) {
						cornerPositions.remove(vertex);
						cornerPositions.put(vertex, position);
						doContinue = true;
						break;
					}
				}
			}

			// if nothing has been done yet and one corner has multiple
			// opportunites, use one
			if (!doContinue) {
				for (Corner vertex : corner) {
					Collection positions = cornerPositions.get(vertex);

					if (positions.size() > 1) {
						Integer position = positions.iterator().next();
						cornerPositions.remove(vertex);
						cornerPositions.put(vertex, position);
						doContinue = true;
						break;
					}
				}
			}
		}
		// now all corners have exactly one position from 0 to 4

		// create the mapping from the position to the corner
		// the index in the array is the position, the value is the index of the
		// corresponding corner/bounds
		int[] indexOfCorner = new int[size];
		for (int i = 0; i < size; i++) {
			indexOfCorner[i] = -1;
		}

		for (int i = 0; i < size; i++) {
			Corner c = corner.get(i);
			Integer pos = cornerPositions.get(c).iterator().next();
			indexOfCorner[pos] = i;
		}



		// create the pentagram

		Point2D point0 = new Point2D.Double(dist
				+ bounds.get(indexOfCorner[1]).width
				+ dist, dist);
		Point2D point1 = new Point2D.Double(dist, dist
				+ bounds.get(indexOfCorner[0]).height + dist
				+ bounds.get(indexOfCorner[4]).height + dist);
		Point2D point2 = new Point2D.Double(dist
				+ bounds.get(indexOfCorner[1]).width + dist
				+ bounds.get(indexOfCorner[0]).width + dist, dist
				+ bounds.get(indexOfCorner[0]).height + dist
				+ bounds.get(indexOfCorner[4]).height + dist
				+ bounds.get(indexOfCorner[1]).height + dist
				+ bounds.get(indexOfCorner[3]).height + dist);
		Point2D point3 = new Point2D.Double(dist
				+ bounds.get(indexOfCorner[1]).width + dist
				+ bounds.get(indexOfCorner[0]).width + dist
				+ bounds.get(indexOfCorner[2]).width + dist, dist
				+ bounds.get(indexOfCorner[0]).height + dist
				+ bounds.get(indexOfCorner[4]).height + dist
				+ bounds.get(indexOfCorner[1]).height + dist);

		// check whether the point4 should be at the same y-position as point0
		boolean point4AtSameHeightAsPoint0 = false;
		if (constraints != null) {
			if (constraints.getObjectsWithEdgesToLowerYButNotHigherY()
					.contains(corner.get(indexOfCorner[4]))
					&& !constraints.getEdgesToHigherX().contains(
							corner.get(indexOfCorner[4]))) {
				point4AtSameHeightAsPoint0 = true;
			}
		}

		// check whether the corner 4 is connected with corner 2
		// this is needed to determine the x-position of corner 4
		boolean point4ConnectedWithPoint2 = graph.findEdge(
				corner.get(indexOfCorner[4]), corner.get(indexOfCorner[2])) != null;
		// if this is the case then point 4 must have the same y position as
		// point 3 to avoid overlapping of the edge with point 3

		Point2D point4 = new Point2D.Double(dist
				+ bounds.get(indexOfCorner[1]).width + dist
				+ bounds.get(indexOfCorner[0]).width + dist
				+ bounds.get(indexOfCorner[2]).width + dist
				+ (point4ConnectedWithPoint2 ? 0
						: bounds.get(indexOfCorner[3]).width + dist), dist
				+ (point4AtSameHeightAsPoint0 ? 0
						: bounds.get(indexOfCorner[0]).height
						+ dist));

		Point2D[] points = { point0, point1, point2, point3, point4 };

		Point2D[] result = new Point2D[size];
		for (int i = 0; i < size; i++) {
			result[indexOfCorner[i]] = points[i];
		}

		// Point2D point0 = new Point2D.Double(dist, dist);
		// Point2D point1 = new Point2D.Double(dist, dist + 2 * maxHeight);
		// Point2D point2 = new Point2D.Double(dist + 2 * maxWidth, dist + 3
		// * maxHeight);
		// Point2D point3 = new Point2D.Double(dist + 4 * maxWidth, dist + 2
		// * maxHeight);
		// Point2D point4 = new Point2D.Double(dist + 4 * maxWidth, dist);

		// result[0] = point0;
		// result[1] = point1;
		// result[2] = point2;
		// result[3] = point3;
		// result[4] = point4;

		return result;
	}

	/**
	 * Checks whether there are overlappings in a graph.
	 *
	 * @param graph
	 *            contains the (overlapping) shapes.
	 * 
	 * @param overlappingAllowedFlag
	 *            are overlappings allowed
	 * @param checkVertexVertex
	 *            check vertex-vertex-overlapping
	 * @param checkVertexEdge
	 *            check vertex-edge-overlapping
	 * @param checkEdgeEdge
	 *            check edge-edge-overlapping
	 * @param constraintsToCreateTestWhenError
	 *            additional constraints that are used when creating the sourcecode of a test when this check fails
	 * @return true, if the check is ok, false otherwise (if no exception is thrown)
	 */
	public static  boolean checkOverlappings(Graph graph,
			ObjectDescription overlappingAllowedFlag, boolean checkVertexVertex,
			boolean checkVertexEdge, boolean checkEdgeEdge,
			GeometryPositionConstraint constraintsToCreateTestWhenError) {
		if (overlappingAllowedFlag == null) {
			return true;
		}
		Tuple>, Collection, Void>>, Collection>, Void> overlappings = GeometryBoostUtils
				.hasOverlappings(graph, true);
		
		Collection> vertexVertexOverlapping = overlappings.getFirst();
		Collection, Void>> vertexEdgeOverlapping = overlappings
				.getSecond();
		Collection> edgeEdgeOverlapping = overlappings.getThird();
		
	
		if ( (checkVertexVertex && ! vertexVertexOverlapping.isEmpty()) || (checkVertexEdge && ! vertexEdgeOverlapping.isEmpty())|| (checkEdgeEdge && ! edgeEdgeOverlapping.isEmpty())) {
			StringBuilder errormessage = new StringBuilder();
			String prefix = overlappingAllowedFlag.getValidationInfo().getExceptionTextPrefix();
			if (prefix != null) {
				errormessage.append(prefix);
			}
			errormessage.append(" overlappings: ");
			if (checkVertexVertex && ! vertexVertexOverlapping.isEmpty()){
				errormessage.append("\nvertex-vertex-overlappings: ").append(vertexVertexOverlapping);
			}
			if (checkVertexEdge && ! vertexEdgeOverlapping.isEmpty()){
				errormessage.append("\nvertex-edge-overlappings: ").append(vertexEdgeOverlapping);
			}
			if (checkEdgeEdge && ! edgeEdgeOverlapping.isEmpty()){
				errormessage.append("\nedge-edge-overlappings: ").append(edgeEdgeOverlapping);
			}
		
			String testcode = createTestSourcecode(graph,
					constraintsToCreateTestWhenError);
			log.info("Testcode is\n", testcode);
			// todo later: trace

			if (overlappingAllowedFlag.getValidationInfo().isThrowExceptionIfValueIsNotValid()) {
				throw new IllegalStateException(errormessage.toString());
			} else {
				log.debug(errormessage);
				return false;
			}
		}
		return true;
	}

	/**
	 * Create sourcecode from a graph
	 * 
	 * @param graph
	 *            the objects to describe
	 * @param constraints
	 *            additional constraints.
	 * @return "no sourcecode yet"
	 */
	public static  String createTestSourcecode(Graph graph,
			GeometryPositionConstraint constraints) {
		return "no sourcecode yet";
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy