net.sourceforge.plantuml.graph2.Plan Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of plantuml Show documentation
Show all versions of plantuml Show documentation
PlantUML is a component that allows to quickly write :
* sequence diagram,
* use case diagram,
* class diagram,
* activity diagram,
* component diagram,
* state diagram
* object diagram
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2013, Arnaud Roques
*
* Project Info: http://plantuml.sourceforge.net
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* Original Author: Arnaud Roques
*
* Revision $Revision: 9786 $
*
*/
package net.sourceforge.plantuml.graph2;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import net.sourceforge.plantuml.Log;
import net.sourceforge.plantuml.graph2.Dijkstra.Vertex;
public class Plan {
private final Map points = new LinkedHashMap();
private final Collection lines = new ArrayList();
public void addPoint2D(Point2D.Double point) {
if (points.containsKey(point)) {
throw new IllegalArgumentException();
}
points.put(point, new Singularity2(point));
}
public void debugPrint() {
Log.println("PLAN PRINT");
for (Singularity2 s : points.values()) {
Log.println("s="+s);
}
for (Line2D.Double l : lines) {
Log.println(GeomUtils.toString(l));
}
}
public void createLink(Point2D p1, Point2D p2) {
final Singularity2 s1 = points.get(p1);
final Singularity2 s2 = points.get(p2);
if (s1 == null || s2 == null) {
throw new IllegalArgumentException();
}
final Line2D.Double line = new Line2D.Double(p1, p2);
s1.addLineSegment(line);
s2.addLineSegment(line);
lines.add(line);
}
Singularity2 getSingularity(Point2D pt) {
final Singularity2 result = points.get(pt);
if (result == null) {
throw new IllegalArgumentException();
}
return result;
}
List getShortestPathToInternal(Point2D start, Point2D end) {
final Dijkstra dijkstra = new Dijkstra();
if (points.containsKey(start) == false || points.containsKey(end) == false) {
throw new IllegalArgumentException();
}
final Vertex vStart = dijkstra.addVertex(start);
final Vertex vEnd = dijkstra.addVertex(end);
final Map vertexes = new LinkedHashMap();
for (Singularity2 s : points.values()) {
for (Neighborhood2 n : s.getNeighborhoods()) {
final Vertex v = dijkstra.addVertex(n);
vertexes.put(n, v);
if (n.getCenter().equals(start)) {
vStart.addAdjacencies(v, 0.01);
}
if (n.getCenter().equals(end)) {
v.addAdjacencies(vEnd, 0.01);
}
}
}
for (Vertex v1 : vertexes.values()) {
for (Vertex v2 : vertexes.values()) {
final Neighborhood2 n1 = (Neighborhood2) v1.getData();
final Neighborhood2 n2 = (Neighborhood2) v2.getData();
if (n1.getCenter().equals(n2.getCenter())) {
continue;
}
final Line2D.Double line = new Line2D.Double(n1.getCenter(), n2.getCenter());
if (isStrictCrossing(line)) {
continue;
}
if (n1.isConnectable(n2) == false) {
continue;
}
final double dist = n1.getCenter().distance(n2.getCenter());
v1.addAdjacencies(v2, dist);
v2.addAdjacencies(v1, dist);
// Log.println("=(" + n1 + ") (" + n2 + ") " + dist);
}
}
final List list = dijkstra.getShortestPathTo(vStart, vEnd);
if (list.size() < 2) {
throw new IllegalStateException("list=" + list);
}
final List result = new ArrayList();
for (Vertex v : list.subList(1, list.size() - 1)) {
result.add((Neighborhood2) v.getData());
}
return result;
}
public List getIntermediatePoints(Point2D start, Point2D end) {
// Log.println("start=" + start + " end=" + end);
final List result = new ArrayList();
final List list = getShortestPathToInternal(start, end);
// Log.println("Neighborhood2 = " + list);
for (int i = 1; i < list.size() - 1; i++) {
final Neighborhood2 n = list.get(i);
final Point2D.Double before = list.get(i - 1).getCenter();
final Point2D.Double after = list.get(i + 1).getCenter();
// Log.println("before="+before);
// Log.println("after="+after);
// Log.println("n.getCenter()="+n.getCenter());
// Log.println("getMindist(n.getCenter())="+getMindist(n.getCenter()));
final Point2D.Double pointInNeighborhood = n.getPointInNeighborhood(getMindist(n.getCenter()) / 2, before,
after);
// Log.println("pointInNeighborhood="+pointInNeighborhood);
result.add(pointInNeighborhood);
}
return result;
}
private boolean isStrictCrossing(Line2D.Double line) {
for (Line2D.Double l : lines) {
if (intersectsLineStrict(l, line)) {
return true;
}
}
return false;
}
public static boolean intersectsLineStrict(Line2D.Double l1, Line2D.Double l2) {
assert intersectsLineStrictInternal(l1, l2) == intersectsLineStrictInternal(l2, l1);
assert intersectsLineStrictInternal(l1, l2) == intersectsLineStrictInternal(inverse(l1), l2);
assert intersectsLineStrictInternal(l1, l2) == intersectsLineStrictInternal(l1, inverse(l2));
assert intersectsLineStrictInternal(l1, l2) == intersectsLineStrictInternal(inverse(l1), inverse(l2));
return intersectsLineStrictInternal(l1, l2);
}
private static Line2D.Double inverse(Line2D.Double line) {
return new Line2D.Double(line.getP2(), line.getP1());
}
private static boolean intersectsLineStrictInternal(Line2D.Double l1, Line2D.Double l2) {
if (l1.intersectsLine(l2) == false) {
return false;
}
assert l1.intersectsLine(l2);
Point2D.Double l1a = (Point2D.Double) l1.getP1();
Point2D.Double l1b = (Point2D.Double) l1.getP2();
Point2D.Double l2a = (Point2D.Double) l2.getP1();
Point2D.Double l2b = (Point2D.Double) l2.getP2();
if (l1a.equals(l2a) == false && l1a.equals(l2b) == false && l1b.equals(l2a) == false
&& l1b.equals(l2b) == false) {
return true;
}
if (l1a.equals(l2b)) {
final Point2D.Double tmp = l2a;
l2a = l2b;
l2b = tmp;
} else if (l2a.equals(l1b)) {
final Point2D.Double tmp = l1a;
l1a = l1b;
l1b = tmp;
} else if (l1b.equals(l2b)) {
Point2D.Double tmp = l2a;
l2a = l2b;
l2b = tmp;
tmp = l1a;
l1a = l1b;
l1b = tmp;
}
assert l1a.equals(l2a);
return false;
}
final double getMindist(Point2D.Double pt) {
double result = Double.MAX_VALUE;
for (Point2D p : points.keySet()) {
if (pt.equals(p)) {
continue;
}
final double v = p.distance(pt);
if (v < 1E-4) {
throw new IllegalStateException();
}
result = Math.min(result, v);
}
for (Line2D line : lines) {
if (line.getP1().equals(pt) || line.getP2().equals(pt)) {
continue;
}
final double v = line.ptSegDist(pt);
if (result < 1E-4) {
throw new IllegalStateException("pt=" + pt + " line=" + GeomUtils.toString(line));
}
result = Math.min(result, v);
}
if (result == 0) {
throw new IllegalStateException();
}
// Log.println("getMindist=" + result);
return result;
}
}