/****************************************************************************** * Copyright (c) 2011, 2016 Stephan Schwiebert and others. * 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: * Stephan Schwiebert - initial API and implementation * *******************************************************************************/ package org.eclipse.gef.cloudio.internal.ui.layout; import java.util.Random; import org.eclipse.core.runtime.Assert; import org.eclipse.gef.cloudio.internal.ui.Word; import org.eclipse.gef.cloudio.internal.ui.util.CloudMatrix; import org.eclipse.gef.cloudio.internal.ui.util.RectTree; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; /** * * @author sschwieb * */ public class DefaultLayouter implements ILayouter { public static final String X_AXIS_VARIATION = "xaxis"; public static final String Y_AXIS_VARIATION = "yaxis"; private Random random = new Random(); /** * Percentage of the x axis variation. By default, searching for free space is * started in the center of the available area. By increasing this value, * the start point is moved on the x axis. * */ private int xAxisVariation; /** * Percentage of the y axis variation. By default, searching for free space is * started in the center of the available area. By increasing this value, * the start point is moved on the y axis. * */ private int yAxisVariation; public DefaultLayouter(int i, int j) { this.xAxisVariation = i; this.yAxisVariation = j; } public Point getInitialOffset(Word word, Rectangle cloudArea) { int xOff = 0; if (xAxisVariation > 0) { int range = (cloudArea.width - word.width) / 200 * xAxisVariation; if (range > 0) { xOff = random.nextInt(range); if (random.nextBoolean()) { xOff = -xOff; } } } int yOff = 0; if (yAxisVariation > 0) { int range = cloudArea.height / 200 * yAxisVariation; if (range > 0) { yOff = random.nextInt(range); if (random.nextBoolean()) yOff = -yOff; } } return new Point(xOff, yOff); } /** * Tries to position the given word in the given area. First a start point * is chosen, then the {@link RectTree} of the word and the main area is * used to detect whether the word can be placed at the given position, or * not. If not, the current point is moved slightly in a spiral manner, * similar to the approach of Wordle. * * @param word * @param cloudArea * @return whether the given word could be placed in the respective cloud * area */ public boolean layout(Point offset, final Word word, final Rectangle cloudArea, CloudMatrix mainTree) { Assert.isLegal(word != null, "Word cannot be null!"); Point next = new Point(-word.width / 2, -word.height / 2); next.x += random.nextInt(25); next.y += random.nextInt(25); double growFactor = 1.6; offset.x += cloudArea.width / 2; offset.y += cloudArea.height / 2; final int accuracy = mainTree.getMinResolution(); for (int i = 0; i < 5000; i++) { final double radius = Math.sqrt((double) (next.x * next.x + next.y * next.y)) + growFactor; double atan = Math.atan2(next.y, next.x); if (growFactor > 1.1) { growFactor -= 0.0007; } if (radius < 80) { atan += 0.7; } else { atan += 20 / radius; } if (growFactor < 0.0005) { growFactor = 0.0005; } next.x = (int) (radius * Math.cos(atan)); next.y = (int) (radius * Math.sin(atan)); word.x = ((next.x + offset.x) / accuracy) * accuracy; word.y = ((next.y + offset.y) / accuracy) * accuracy; RectTree rt = word.tree; if (rt == null) break; rt.move(word.x, word.y); if (cloudArea.x <= word.x && cloudArea.y <= word.y && cloudArea.x + cloudArea.width >= word.x + word.width && cloudArea.y + cloudArea.height >= word.y + word.height) { if (rt.fits(mainTree)) { rt.place(mainTree, word.id); return true; } } } return false; } public void setOption(String optionName, Object object) { if (X_AXIS_VARIATION.equals(optionName)) { Integer value = (Integer) object; Assert.isLegal(value >= 0, "Parameter must be between 0 and 100 (inclusive): " + value); Assert.isLegal(value <= 100, "Parameter must be between 0 and 100 (inclusive): " + value); this.xAxisVariation = value; return; } if (Y_AXIS_VARIATION.equals(optionName)) { Integer value = (Integer) object; Assert.isLegal(value >= 0, "Parameter must be between 0 and 100 (inclusive): " + value); Assert.isLegal(value <= 100, "Parameter must be between 0 and 100 (inclusive): " + value); this.yAxisVariation = value; return; } System.err.println("Unrecognized option: " + optionName); } }