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

net.sourceforge.plantuml.golem.TilesField Maven / Gradle / Ivy

// THIS FILE HAS BEEN GENERATED BY A PREPROCESSOR.
/* +=======================================================================
 * |
 * |      PlantUML : a free UML diagram generator
 * |
 * +=======================================================================
 *
 * (C) Copyright 2009-2024, Arnaud Roques
 *
 * Project Info:  https://plantuml.com
 *
 * If you like this project or if you find it useful, you can support us at:
 *
 * https://plantuml.com/patreon (only 1$ per month!)
 * https://plantuml.com/liberapay (only 1€ per month!)
 * https://plantuml.com/paypal
 *
 *
 * PlantUML is free software; you can redistribute it and/or modify it
 * under the terms of the Revised BSD License.
 *
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * * Neither the name of the University of California, Berkeley nor the
 *   names of its contributors may be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * PlantUML can occasionally display sponsored or advertising messages. Those
 * messages are usually generated on welcome or error images and never on
 * functional diagrams.
 * See https://plantuml.com/professional if you want to remove them
 *
 * Images (whatever their format : PNG, SVG, EPS...) generated by running PlantUML
 * are owned by the author of their corresponding sources code (that is, their
 * textual description in PlantUML language). Those images are not covered by
 * this BSD license.
 *
 * The generated images can then be used without any reference to the BSD license.
 * It is not even necessary to stipulate that they have been generated with PlantUML,
 * although this will be appreciated by the PlantUML team.
 *
 * There is an exception : if the textual description in PlantUML language is also covered
 * by any license, then the generated images are logically covered
 * by the very same license.
 *
 * This is the IGY distribution (Install GraphViz by Yourself).
 * You have to install GraphViz and to setup the GRAPHVIZ_DOT environment variable
 * (see https://plantuml.com/graphviz-dot )
 *
 * Icons provided by OpenIconic :  https://useiconic.com/open
 * Archimate sprites provided by Archi :  http://www.archimatetool.com
 * Stdlib AWS provided by https://github.com/milo-minderbinder/AWS-PlantUML
 * Stdlib Icons provided https://github.com/tupadr3/plantuml-icon-font-sprites
 * ASCIIMathML (c) Peter Jipsen http://www.chapman.edu/~jipsen
 * ASCIIMathML (c) David Lippman http://www.pierce.ctc.edu/dlippman
 * CafeUndZopfli ported by Eugene Klyuchnikov https://github.com/eustas/CafeUndZopfli
 * Brotli (c) by the Brotli Authors https://github.com/google/brotli
 * Themes (c) by Brett Schwarz https://github.com/bschwarz/puml-themes
 * Twemoji (c) by Twitter at https://twemoji.twitter.com/
 *
 */
package net.sourceforge.plantuml.golem;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import net.sourceforge.plantuml.klimt.UTranslate;
import net.sourceforge.plantuml.klimt.color.HColors;
import net.sourceforge.plantuml.klimt.drawing.UGraphic;
import net.sourceforge.plantuml.klimt.font.StringBounder;
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
import net.sourceforge.plantuml.klimt.geom.XPoint2D;
import net.sourceforge.plantuml.klimt.shape.AbstractTextBlock;
import net.sourceforge.plantuml.klimt.shape.TextBlock;
import net.sourceforge.plantuml.klimt.shape.ULine;

public class TilesField extends AbstractTextBlock implements TextBlock {

	private int size = 1;
	private final Tile root = new Tile(0);
	private final Map positions = new HashMap();
	private final List paths = new ArrayList<>();

	public TilesField() {
		positions.put(root, new Position(0, 0, 1, 1));
	}

	public Tile getRoot() {
		return root;
	}

	public Tile createTile(Tile start, TileGeometry position) {
		final Tile result = new Tile(size++);
		final Position p = getFreePosition(start, position);
		positions.put(result, p);
		paths.add(buildPath(start.getArea(position), result.getArea(position.opposite())));
		return result;
	}

	public void addPath(Tile start, Tile dest, TileGeometry startDirection) {
		paths.add(buildPath(start.getArea(startDirection), dest.getArea(startDirection.opposite())));
	}

	private Path buildPath(TileArea tileArea1, TileArea tileArea2) {
		if (isAdjoining(tileArea1, tileArea2)) {
			return Path.build(tileArea1, tileArea2);
		}
		final Tile tile1 = tileArea1.getTile();
		final Tile tile2 = tileArea2.getTile();
		final Position pos1 = getPosition(tile1);
		final Position pos2 = getPosition(tile2);
		final TileGeometry geom1 = tileArea1.getGeometry();
		final TileGeometry geom2 = tileArea2.getGeometry();
		if (pos1.getYmin() == pos2.getYmin() && pos1.getYmax() == pos2.getYmax() && geom1 == TileGeometry.WEST
				&& geom2 == TileGeometry.EAST) {
			return Path.build(tileArea1, tileArea2);

		}
		throw new IllegalArgumentException();
	}

	private boolean isAdjoining(TileArea tileArea1, TileArea tileArea2) {
		final Tile tile1 = tileArea1.getTile();
		final Tile tile2 = tileArea2.getTile();
		final Position pos1 = getPosition(tile1);
		final Position pos2 = getPosition(tile2);
		final TileGeometry geom1 = tileArea1.getGeometry();
		final TileGeometry geom2 = tileArea2.getGeometry();
		if (pos1.equals(pos2)) {
			assert tile1 == tile2;
			if (geom1 == geom2) {
				throw new IllegalArgumentException();
			}
			return true;
		}
		if (geom1.equals(geom2.opposite()) == false) {
			return false;
		}
		switch (geom1) {
		case EAST:
			return pos1.getYmin() == pos2.getYmin() && pos1.getYmax() == pos2.getYmax()
					&& pos1.getXmax() + 1 == pos2.getXmin();
		case WEST:
			return pos1.getYmin() == pos2.getYmin() && pos1.getYmax() == pos2.getYmax()
					&& pos1.getXmin() == pos2.getXmax() + 1;
		case SOUTH:
			return pos1.getXmin() == pos2.getXmin() && pos1.getXmax() == pos2.getXmax()
					&& pos1.getYmax() + 1 == pos2.getYmin();
		case NORTH:
			return pos1.getXmin() == pos2.getXmin() && pos1.getXmax() == pos2.getXmax()
					&& pos1.getYmin() == pos2.getYmax() + 1;
		case CENTER:
			return false;

		default:
			throw new IllegalStateException();
		}

	}

	private Tile getTileAt(Position p) {
		for (Map.Entry ent : positions.entrySet()) {
			if (p.equals(ent.getValue())) {
				return ent.getKey();
			}
		}
		return null;
	}

	private Position getFreePosition(Tile start, TileGeometry position) {
		final Position p = getPosition(start).move(position, 2);
		while (isOccuped(p)) {
			// p = p.move(TileGeometry.EAST, 2);
			moveAllToEast(p);
		}
		return p;
	}

	private void moveAllToEast(Position startingPosition) {
		final List toMove = new ArrayList<>();
		for (Position p : positions.values()) {
			if (p.getXmax() < startingPosition.getXmin()) {
				continue;
			}
			if (p.getYmax() < startingPosition.getYmin()) {
				continue;
			}
			toMove.add(p);
		}
		for (Position p : toMove) {
			positions.put(getTileAt(p), p.move(TileGeometry.EAST, 2));
		}

	}

	private boolean isOccuped(Position test) {
		for (Position p : positions.values()) {
			if (p.equals(test)) {
				return true;
			}
		}
		return false;
	}

	public Position getPosition(Tile tile) {
		final Position result = Objects.requireNonNull(positions.get(tile));
		return result;
	}

	private int getXmin() {
		int result = Integer.MAX_VALUE;
		for (Position p : positions.values()) {
			final int v = p.getXmin();
			if (v < result) {
				result = v;
			}
		}
		return result;
	}

	private int getYmin() {
		int result = Integer.MAX_VALUE;
		for (Position p : positions.values()) {
			final int v = p.getYmin();
			if (v < result) {
				result = v;
			}
		}
		return result;
	}

	private int getXmax() {
		int result = Integer.MIN_VALUE;
		for (Position p : positions.values()) {
			final int v = p.getXmax();
			if (v > result) {
				result = v;
			}
		}
		return result;
	}

	private int getYmax() {
		int result = Integer.MIN_VALUE;
		for (Position p : positions.values()) {
			final int v = p.getYmax();
			if (v > result) {
				result = v;
			}
		}
		return result;
	}

	public List getPaths() {
		return Collections.unmodifiableList(paths);
	}

	// -----------
	public void drawU(UGraphic ug) {
		double x = 0;
		double y = 0;
		final int xmin = getXmin();
		final int ymin = getYmin();
		final XDimension2D dimSingle = root.calculateDimension(ug.getStringBounder());
		x -= xmin * dimSingle.getWidth() / 2;
		y -= ymin * dimSingle.getHeight() / 2;
		for (Map.Entry ent : positions.entrySet()) {
			final Position p = ent.getValue();
			final Tile t = ent.getKey();
			final double xt = p.getXmin() * dimSingle.getWidth() / 2;
			final double yt = p.getYmin() * dimSingle.getHeight() / 2;
			t.drawU(ug.apply(new UTranslate((x + xt), (y + yt))));
		}
		ug = ug.apply(HColors.RED);
		for (Path p : paths) {
			final TileArea start = p.getStart();
			final TileArea dest = p.getDest();
			final XPoint2D pstart = getPoint2D(dimSingle, start);
			final XPoint2D pdest = getPoint2D(dimSingle, dest);
			ug.apply(new UTranslate(x + pstart.getX(), y + pstart.getY()))
					.draw(new ULine(pdest.getX() - pstart.getX(), pdest.getY() - pstart.getY()));
		}
	}

	private XPoint2D getPoint2D(XDimension2D dimSingle, TileArea area) {
		final Position p = getPosition(area.getTile());
		double xt = p.getXmin() * dimSingle.getWidth() / 2;
		double yt = p.getYmin() * dimSingle.getHeight() / 2;
		xt += dimSingle.getWidth() / 2;
		yt += dimSingle.getHeight() / 2;
		final double coef = 0.33;
		switch (area.getGeometry()) {
		case NORTH:
			yt -= dimSingle.getHeight() * coef;
			break;
		case SOUTH:
			yt += dimSingle.getHeight() * coef;
			break;
		case EAST:
			xt += dimSingle.getWidth() * coef;
			break;
		case WEST:
			xt -= dimSingle.getWidth() * coef;
			break;
		default:
			throw new IllegalStateException();
		}
		return new XPoint2D(xt, yt);
	}

	public XDimension2D calculateDimension(StringBounder stringBounder) {
		final int xmin = getXmin();
		final int xmax = getXmax();
		final int ymin = getYmin();
		final int ymax = getYmax();
		final int width = (xmax - xmin) / 2 + 1;
		final int height = (ymax - ymin) / 2 + 1;
		final XDimension2D dimSingle = root.calculateDimension(stringBounder);
		return new XDimension2D(width * dimSingle.getWidth(), height * dimSingle.getHeight());
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy