1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-06-03 09:00:48 +00:00
plantuml/src/net/sourceforge/plantuml/svek/Line.java

943 lines
30 KiB
Java
Raw Normal View History

2011-08-08 17:48:29 +00:00
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
2016-01-09 12:15:40 +00:00
* (C) Copyright 2009-2017, Arnaud Roques
2011-08-08 17:48:29 +00:00
*
2016-03-06 16:47:34 +00:00
* Project Info: http://plantuml.com
2011-08-08 17:48:29 +00:00
*
2017-03-15 19:13:31 +00:00
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
2011-08-08 17:48:29 +00:00
* 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
2013-12-10 19:36:50 +00:00
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
2011-08-08 17:48:29 +00:00
* 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.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.svek;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
2013-12-10 19:36:50 +00:00
import java.util.Collection;
2011-08-08 17:48:29 +00:00
import java.util.List;
2017-10-07 09:46:53 +00:00
import net.sourceforge.plantuml.ColorParam;
2016-09-29 19:51:18 +00:00
import net.sourceforge.plantuml.Dimension2DDouble;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.Direction;
import net.sourceforge.plantuml.Hideable;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.ISkinParam;
2017-10-07 09:46:53 +00:00
import net.sourceforge.plantuml.LineParam;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.Log;
2015-04-07 18:18:37 +00:00
import net.sourceforge.plantuml.Pragma;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.StringUtils;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.Url;
2011-09-07 20:41:58 +00:00
import net.sourceforge.plantuml.command.Position;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.cucadiagram.Display;
2016-07-04 19:06:50 +00:00
import net.sourceforge.plantuml.cucadiagram.EntityPort;
2011-09-08 10:42:27 +00:00
import net.sourceforge.plantuml.cucadiagram.IEntity;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.cucadiagram.IGroup;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.cucadiagram.Link;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.cucadiagram.LinkArrow;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.cucadiagram.LinkDecor;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.cucadiagram.LinkMiddleDecor;
2015-04-07 18:18:37 +00:00
import net.sourceforge.plantuml.cucadiagram.LinkType;
2016-09-29 19:51:18 +00:00
import net.sourceforge.plantuml.cucadiagram.NoteLinkStrategy;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.cucadiagram.dot.GraphvizVersion;
2015-06-07 10:23:10 +00:00
import net.sourceforge.plantuml.graphic.AbstractTextBlock;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.graphic.FontConfiguration;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.graphic.HtmlColor;
2017-10-07 09:46:53 +00:00
import net.sourceforge.plantuml.graphic.HtmlColorUtils;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.graphic.TextBlockArrow;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.graphic.TextBlockUtils;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.graphic.UDrawable;
2015-04-07 18:18:37 +00:00
import net.sourceforge.plantuml.graphic.USymbolFolder;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.graphic.VerticalAlignment;
2015-09-28 20:42:17 +00:00
import net.sourceforge.plantuml.graphic.color.ColorType;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.posimo.BezierUtils;
import net.sourceforge.plantuml.posimo.DotPath;
2011-09-08 10:42:27 +00:00
import net.sourceforge.plantuml.posimo.Moveable;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.posimo.Positionable;
2011-09-07 20:41:58 +00:00
import net.sourceforge.plantuml.posimo.PositionableUtils;
2016-03-06 16:47:34 +00:00
import net.sourceforge.plantuml.svek.extremity.Extremity;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.svek.extremity.ExtremityFactory;
2017-02-01 18:55:51 +00:00
import net.sourceforge.plantuml.svek.extremity.ExtremityFactoryExtends;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.svek.image.EntityImageNoteLink;
import net.sourceforge.plantuml.ugraphic.UChangeBackColor;
import net.sourceforge.plantuml.ugraphic.UChangeColor;
2017-04-26 17:48:37 +00:00
import net.sourceforge.plantuml.ugraphic.UComment;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.ugraphic.UGraphic;
2017-06-05 11:27:21 +00:00
import net.sourceforge.plantuml.ugraphic.ULine;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.ugraphic.UPolygon;
import net.sourceforge.plantuml.ugraphic.UShape;
import net.sourceforge.plantuml.ugraphic.UStroke;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.ugraphic.UTranslate;
2011-08-08 17:48:29 +00:00
2013-12-10 19:36:50 +00:00
public class Line implements Moveable, Hideable {
2011-08-08 17:48:29 +00:00
2016-01-09 12:15:40 +00:00
private final Cluster ltail;
private final Cluster lhead;
2011-08-08 17:48:29 +00:00
private final Link link;
2016-07-04 19:06:50 +00:00
private final EntityPort startUid;
private final EntityPort endUid;
2011-08-08 17:48:29 +00:00
private final TextBlock startTailText;
private final TextBlock endHeadText;
2015-09-28 20:42:17 +00:00
private final TextBlock labelText;
2016-09-29 19:51:18 +00:00
private boolean divideLabelWidthByTwo = false;
2011-08-08 17:48:29 +00:00
private final int lineColor;
2011-09-07 20:41:58 +00:00
private final int noteLabelColor;
2011-08-08 17:48:29 +00:00
private final int startTailColor;
private final int endHeadColor;
2013-12-10 19:36:50 +00:00
private final StringBounder stringBounder;
private final Bibliotekon bibliotekon;
private DotPath dotPath;
2011-09-07 20:41:58 +00:00
private Positionable startTailLabelXY;
private Positionable endHeadLabelXY;
2015-09-28 20:42:17 +00:00
private Positionable labelXY;
2011-08-08 17:48:29 +00:00
2013-12-10 19:36:50 +00:00
private UDrawable extremity2;
private UDrawable extremity1;
2011-08-08 17:48:29 +00:00
2013-12-10 19:36:50 +00:00
private double dx;
private double dy;
private boolean opale;
private Cluster projectionCluster;
2015-04-07 18:18:37 +00:00
private final Pragma pragma;
2016-06-19 14:16:41 +00:00
private final HtmlColor backgroundColor;
2017-06-05 11:27:21 +00:00
private final boolean useRankSame;
2017-10-07 09:46:53 +00:00
private final UStroke defaultThickness;
private HtmlColor arrowLollipopColor;
2013-12-10 19:36:50 +00:00
@Override
public String toString() {
return super.toString() + " color=" + lineColor;
}
2015-06-07 10:23:10 +00:00
class DirectionalTextBlock extends AbstractTextBlock implements TextBlock {
2013-12-10 19:36:50 +00:00
private final TextBlock right;
private final TextBlock left;
private final TextBlock up;
private final TextBlock down;
DirectionalTextBlock(TextBlock right, TextBlock left, TextBlock up, TextBlock down) {
this.right = right;
this.left = left;
this.up = up;
this.down = down;
}
public void drawU(UGraphic ug) {
Direction dir = getDirection();
if (getLinkArrow() == LinkArrow.BACKWARD) {
dir = dir.getInv();
}
switch (dir) {
case RIGHT:
right.drawU(ug);
break;
case LEFT:
left.drawU(ug);
break;
case UP:
up.drawU(ug);
break;
case DOWN:
down.drawU(ug);
break;
default:
throw new UnsupportedOperationException();
}
}
public Dimension2D calculateDimension(StringBounder stringBounder) {
return right.calculateDimension(stringBounder);
}
private Direction getDirection() {
if (isAutolink()) {
final double startAngle = dotPath.getStartAngle();
return Direction.LEFT;
}
final Point2D start = dotPath.getStartPoint();
final Point2D end = dotPath.getEndPoint();
final double ang = Math.atan2(end.getX() - start.getX(), end.getY() - start.getY());
if (ang > -Math.PI / 4 && ang < Math.PI / 4) {
return Direction.DOWN;
}
if (ang > Math.PI * 3 / 4 || ang < -Math.PI * 3 / 4) {
return Direction.UP;
}
return end.getX() > start.getX() ? Direction.RIGHT : Direction.LEFT;
}
}
2016-07-04 19:06:50 +00:00
private Cluster getCluster2(Bibliotekon bibliotekon, IEntity entityMutable) {
for (Cluster cl : bibliotekon.allCluster()) {
if (entityMutable == cl.getGroup()) {
return cl;
}
}
throw new IllegalArgumentException();
}
2011-08-08 17:48:29 +00:00
2016-07-04 19:06:50 +00:00
public Line(Link link, ColorSequence colorSequence, ISkinParam skinParam, StringBounder stringBounder,
FontConfiguration labelFont, Bibliotekon bibliotekon, Pragma pragma) {
if (link == null) {
2011-08-08 17:48:29 +00:00
throw new IllegalArgumentException();
}
2017-06-05 11:27:21 +00:00
this.useRankSame = skinParam.useRankSame();
2016-07-04 19:06:50 +00:00
this.startUid = link.getEntityPort1(bibliotekon);
this.endUid = link.getEntityPort2(bibliotekon);
Cluster ltail = null;
if (startUid.startsWith(Cluster.CENTER_ID)) {
ltail = getCluster2(bibliotekon, link.getEntity1());
}
Cluster lhead = null;
if (endUid.startsWith(Cluster.CENTER_ID)) {
lhead = getCluster2(bibliotekon, link.getEntity2());
}
2015-09-28 20:42:17 +00:00
if (link.getColors() != null) {
skinParam = link.getColors().mute(skinParam);
labelFont = labelFont.mute(link.getColors());
}
2016-06-19 14:16:41 +00:00
this.backgroundColor = skinParam.getBackgroundColor();
2017-10-07 09:46:53 +00:00
this.defaultThickness = skinParam.getThickness(LineParam.arrow, null);
this.arrowLollipopColor = skinParam.getHtmlColor(ColorParam.arrowLollipop, null, false);
if (arrowLollipopColor == null) {
this.arrowLollipopColor = HtmlColorUtils.WHITE;
}
2015-04-07 18:18:37 +00:00
this.pragma = pragma;
2013-12-10 19:36:50 +00:00
this.bibliotekon = bibliotekon;
2011-08-08 17:48:29 +00:00
this.stringBounder = stringBounder;
this.link = link;
this.ltail = ltail;
this.lhead = lhead;
this.lineColor = colorSequence.getValue();
2011-09-07 20:41:58 +00:00
this.noteLabelColor = colorSequence.getValue();
2011-08-08 17:48:29 +00:00
this.startTailColor = colorSequence.getValue();
this.endHeadColor = colorSequence.getValue();
2011-09-07 20:41:58 +00:00
final TextBlock labelOnly;
2015-07-11 09:32:49 +00:00
if (Display.isNull(link.getLabel())) {
2013-12-10 19:36:50 +00:00
if (getLinkArrow() == LinkArrow.NONE) {
labelOnly = null;
} else {
final TextBlockArrow right = new TextBlockArrow(Direction.RIGHT, labelFont);
final TextBlockArrow left = new TextBlockArrow(Direction.LEFT, labelFont);
final TextBlockArrow up = new TextBlockArrow(Direction.UP, labelFont);
final TextBlockArrow down = new TextBlockArrow(Direction.DOWN, labelFont);
labelOnly = new DirectionalTextBlock(right, left, up, down);
}
2011-08-08 17:48:29 +00:00
} else {
2016-07-04 19:06:50 +00:00
final double marginLabel = startUid.equalsId(endUid) ? 6 : 1;
2013-12-10 19:36:50 +00:00
final TextBlock label = TextBlockUtils.withMargin(
2016-07-04 19:06:50 +00:00
link.getLabel().create(labelFont, skinParam.getDefaultTextAlignment(HorizontalAlignment.CENTER),
2017-02-26 16:26:11 +00:00
skinParam, skinParam.maxMessageSize()), marginLabel, marginLabel);
2013-12-10 19:36:50 +00:00
if (getLinkArrow() == LinkArrow.NONE) {
labelOnly = label;
} else {
TextBlock right = new TextBlockArrow(Direction.RIGHT, labelFont);
right = TextBlockUtils.mergeLR(label, right, VerticalAlignment.CENTER);
TextBlock left = new TextBlockArrow(Direction.LEFT, labelFont);
left = TextBlockUtils.mergeLR(left, label, VerticalAlignment.CENTER);
TextBlock up = new TextBlockArrow(Direction.UP, labelFont);
up = TextBlockUtils.mergeTB(up, label, HorizontalAlignment.CENTER);
TextBlock down = new TextBlockArrow(Direction.DOWN, labelFont);
down = TextBlockUtils.mergeTB(label, down, HorizontalAlignment.CENTER);
labelOnly = new DirectionalTextBlock(right, left, up, down);
}
2011-08-08 17:48:29 +00:00
}
2011-09-07 20:41:58 +00:00
final TextBlock noteOnly;
if (link.getNote() == null) {
noteOnly = null;
} else {
2015-09-28 20:42:17 +00:00
noteOnly = new EntityImageNoteLink(link.getNote(), link.getNoteColors(), skinParam);
2016-09-29 19:51:18 +00:00
if (link.getNoteLinkStrategy() == NoteLinkStrategy.HALF_NOT_PRINTED
|| link.getNoteLinkStrategy() == NoteLinkStrategy.HALF_PRINTED_FULL) {
divideLabelWidthByTwo = true;
}
2011-09-07 20:41:58 +00:00
}
if (labelOnly != null && noteOnly != null) {
if (link.getNotePosition() == Position.LEFT) {
2015-09-28 20:42:17 +00:00
labelText = TextBlockUtils.mergeLR(noteOnly, labelOnly, VerticalAlignment.CENTER);
2011-09-07 20:41:58 +00:00
} else if (link.getNotePosition() == Position.RIGHT) {
2015-09-28 20:42:17 +00:00
labelText = TextBlockUtils.mergeLR(labelOnly, noteOnly, VerticalAlignment.CENTER);
2011-09-07 20:41:58 +00:00
} else if (link.getNotePosition() == Position.TOP) {
2015-09-28 20:42:17 +00:00
labelText = TextBlockUtils.mergeTB(noteOnly, labelOnly, HorizontalAlignment.CENTER);
2011-09-07 20:41:58 +00:00
} else {
2015-09-28 20:42:17 +00:00
labelText = TextBlockUtils.mergeTB(labelOnly, noteOnly, HorizontalAlignment.CENTER);
2011-09-07 20:41:58 +00:00
}
} else if (labelOnly != null) {
2015-09-28 20:42:17 +00:00
labelText = labelOnly;
2011-09-07 20:41:58 +00:00
} else if (noteOnly != null) {
2015-09-28 20:42:17 +00:00
labelText = noteOnly;
2011-09-07 20:41:58 +00:00
} else {
2015-09-28 20:42:17 +00:00
labelText = null;
2011-09-07 20:41:58 +00:00
}
2011-08-08 17:48:29 +00:00
if (link.getQualifier1() == null) {
startTailText = null;
} else {
2015-09-28 20:42:17 +00:00
startTailText = Display.getWithNewlines(link.getQualifier1()).create(labelFont, HorizontalAlignment.CENTER,
skinParam);
2011-08-08 17:48:29 +00:00
}
if (link.getQualifier2() == null) {
endHeadText = null;
} else {
2015-09-28 20:42:17 +00:00
endHeadText = Display.getWithNewlines(link.getQualifier2()).create(labelFont, HorizontalAlignment.CENTER,
skinParam);
2011-08-08 17:48:29 +00:00
}
}
2013-12-10 19:36:50 +00:00
public boolean hasNoteLabelText() {
2015-09-28 20:42:17 +00:00
return labelText != null;
2013-12-10 19:36:50 +00:00
}
private LinkArrow getLinkArrow() {
return link.getLinkArrow();
}
2016-11-04 21:39:29 +00:00
public void appendLine(GraphvizVersion graphvizVersion, StringBuilder sb, DotMode dotMode) {
2013-12-10 19:36:50 +00:00
// Log.println("inverted=" + isInverted());
// if (isInverted()) {
// sb.append(endUid);
// sb.append("->");
// sb.append(startUid);
// } else {
2016-07-04 19:06:50 +00:00
sb.append(startUid.getFullString());
2011-08-08 17:48:29 +00:00
sb.append("->");
2016-07-04 19:06:50 +00:00
sb.append(endUid.getFullString());
2013-12-10 19:36:50 +00:00
// }
2011-08-08 17:48:29 +00:00
sb.append("[");
2016-01-30 12:20:07 +00:00
final LinkType linkType = link.getTypePatchCluster();
2015-04-07 18:18:37 +00:00
String decoration = linkType.getSpecificDecorationSvek();
2017-06-05 11:27:21 +00:00
if (decoration.length() > 0 && decoration.endsWith(",") == false) {
2011-08-08 17:48:29 +00:00
decoration += ",";
}
sb.append(decoration);
2013-12-10 19:36:50 +00:00
int length = link.getLength();
2018-05-01 17:26:04 +00:00
if (graphvizVersion.ignoreHorizontalLinks() && length == 1) {
length = 2;
}
2017-06-05 11:27:21 +00:00
if (useRankSame) {
if (pragma.horizontalLineBetweenDifferentPackageAllowed() || link.isInvis() || length != 1) {
// if (graphvizVersion.isJs() == false) {
sb.append("minlen=" + (length - 1));
sb.append(",");
// }
}
} else {
2013-12-10 19:36:50 +00:00
sb.append("minlen=" + (length - 1));
2011-08-08 17:48:29 +00:00
sb.append(",");
}
sb.append("color=\"" + StringUtils.getAsHtml(lineColor) + "\"");
2015-09-28 20:42:17 +00:00
if (labelText != null) {
2011-08-08 17:48:29 +00:00
sb.append(",");
2018-05-01 17:26:04 +00:00
if (graphvizVersion.useXLabelInsteadOfLabel() || dotMode == DotMode.NO_LEFT_RIGHT_AND_XLABEL) {
2016-06-19 14:16:41 +00:00
sb.append("xlabel=<");
} else {
sb.append("label=<");
}
2016-09-29 19:51:18 +00:00
appendTable(sb, eventuallyDivideByTwo(labelText.calculateDimension(stringBounder)), noteLabelColor,
graphvizVersion);
2011-08-08 17:48:29 +00:00
sb.append(">");
2013-12-10 19:36:50 +00:00
// sb.append(",labelfloat=true");
2011-08-08 17:48:29 +00:00
}
if (startTailText != null) {
sb.append(",");
sb.append("taillabel=<");
2016-06-19 14:16:41 +00:00
appendTable(sb, startTailText.calculateDimension(stringBounder), startTailColor, graphvizVersion);
2011-08-08 17:48:29 +00:00
sb.append(">");
2013-12-10 19:36:50 +00:00
// sb.append(",labelangle=0");
2011-08-08 17:48:29 +00:00
}
if (endHeadText != null) {
sb.append(",");
sb.append("headlabel=<");
2016-06-19 14:16:41 +00:00
appendTable(sb, endHeadText.calculateDimension(stringBounder), endHeadColor, graphvizVersion);
2011-08-08 17:48:29 +00:00
sb.append(">");
2013-12-10 19:36:50 +00:00
// sb.append(",labelangle=0");
2011-08-08 17:48:29 +00:00
}
if (link.isInvis()) {
sb.append(",");
sb.append("style=invis");
}
2013-12-10 19:36:50 +00:00
if (link.isConstraint() == false || link.hasTwoEntryPointsSameContainer()) {
2015-04-07 18:18:37 +00:00
sb.append(",constraint=false");
2013-12-10 19:36:50 +00:00
}
2015-04-07 18:18:37 +00:00
if (link.getSametail() != null) {
sb.append(",sametail=" + link.getSametail());
}
2013-12-10 19:36:50 +00:00
2011-08-08 17:48:29 +00:00
sb.append("];");
SvekUtils.println(sb);
}
2016-09-29 19:51:18 +00:00
private Dimension2D eventuallyDivideByTwo(Dimension2D dim) {
if (divideLabelWidthByTwo) {
return new Dimension2DDouble(dim.getWidth() / 2, dim.getHeight());
}
return dim;
}
2011-08-08 17:48:29 +00:00
public String rankSame() {
2013-12-10 19:36:50 +00:00
// if (graphvizVersion == GraphvizVersion.V2_34_0) {
// return null;
// }
2016-06-19 14:16:41 +00:00
if (pragma.horizontalLineBetweenDifferentPackageAllowed() == false && link.getLength() == 1
/* && graphvizVersion.isJs() == false */) {
2016-07-04 19:06:50 +00:00
return "{rank=same; " + getStartUidPrefix() + "; " + getEndUidPrefix() + "}";
2011-08-08 17:48:29 +00:00
}
return null;
}
2016-06-19 14:16:41 +00:00
public static void appendTable(StringBuilder sb, Dimension2D dim, int col, GraphvizVersion graphvizVersion) {
2011-08-08 17:48:29 +00:00
final int w = (int) dim.getWidth();
final int h = (int) dim.getHeight();
appendTable(sb, w, h, col);
}
public static void appendTable(StringBuilder sb, int w, int h, int col) {
sb.append("<TABLE ");
sb.append("BGCOLOR=\"" + StringUtils.getAsHtml(col) + "\" ");
sb.append("FIXEDSIZE=\"TRUE\" WIDTH=\"" + w + "\" HEIGHT=\"" + h + "\">");
sb.append("<TR");
sb.append(">");
sb.append("<TD");
// sb.append(" FIXEDSIZE=\"TRUE\" WIDTH=\"" + 0 + "\" HEIGHT=\"" + 0 +
// "\"");
sb.append(">");
sb.append("</TD>");
sb.append("</TR>");
sb.append("</TABLE>");
}
2016-07-04 19:06:50 +00:00
public final String getStartUidPrefix() {
return startUid.getPrefix();
2011-08-08 17:48:29 +00:00
}
2016-07-04 19:06:50 +00:00
public final String getEndUidPrefix() {
return endUid.getPrefix();
2011-08-08 17:48:29 +00:00
}
2017-06-05 11:27:21 +00:00
private UDrawable getExtremity(LinkDecor decor, PointListIterator pointListIterator, final Point2D center,
double angle, Cluster cluster, Shape shapeContact) {
2016-06-19 14:16:41 +00:00
final ExtremityFactory extremityFactory = decor.getExtremityFactory(backgroundColor);
2013-12-10 19:36:50 +00:00
2016-03-06 16:47:34 +00:00
if (cluster != null) {
2016-01-09 12:15:40 +00:00
if (extremityFactory != null) {
// System.err.println("angle=" + angle * 180 / Math.PI);
2016-12-14 21:01:03 +00:00
return extremityFactory.createUDrawable(center, angle, null);
2016-01-09 12:15:40 +00:00
}
2017-02-01 18:55:51 +00:00
if (decor == LinkDecor.EXTENDS) {
return new ExtremityFactoryExtends(backgroundColor).createUDrawable(center, angle, null);
}
2016-01-09 12:15:40 +00:00
return null;
}
2013-12-10 19:36:50 +00:00
if (extremityFactory != null) {
final List<Point2D.Double> points = pointListIterator.next();
2017-04-05 17:37:42 +00:00
if (points.size() == 0) {
2017-06-05 11:27:21 +00:00
return extremityFactory.createUDrawable(center, angle, null);
2017-04-05 17:37:42 +00:00
}
2013-12-10 19:36:50 +00:00
final Point2D p0 = points.get(0);
final Point2D p1 = points.get(1);
final Point2D p2 = points.get(2);
2016-12-14 21:01:03 +00:00
Side side = null;
if (shapeContact != null) {
side = shapeContact.getClusterPosition().getClosestSide(p1);
}
return extremityFactory.createUDrawable(p0, p1, p2, side);
2017-06-05 11:27:21 +00:00
} else if (decor == LinkDecor.NONE) {
final UPolygon sh = new UPolygon(pointListIterator.cloneMe().next());
final Point2D contact = sh.checkMiddleContactForSpecificTriangle(center);
if (contact != null) {
return new UDrawable() {
public void drawU(UGraphic ug) {
ULine line = new ULine(contact.getX() - center.getX(), contact.getY() - center.getY());
ug = ug.apply(new UTranslate(center));
ug.draw(line);
}
};
}
2013-12-10 19:36:50 +00:00
} else if (decor != LinkDecor.NONE) {
final UShape sh = new UPolygon(pointListIterator.next());
return new UDrawable() {
public void drawU(UGraphic ug) {
ug.draw(sh);
}
};
}
return null;
}
2018-03-09 21:37:34 +00:00
public void solveLine(SvgResult fullSvg, MinFinder corner1) {
2011-08-08 17:48:29 +00:00
if (this.link.isInvis()) {
return;
}
2018-03-09 21:37:34 +00:00
int idx = fullSvg.getIndexFromColor(this.lineColor);
2011-08-08 17:48:29 +00:00
if (idx == -1) {
2013-12-10 19:36:50 +00:00
return;
// throw new IllegalStateException();
2011-08-08 17:48:29 +00:00
}
2018-03-09 21:37:34 +00:00
idx = fullSvg.indexOf("d=\"", idx);
2011-08-08 17:48:29 +00:00
if (idx == -1) {
throw new IllegalStateException();
}
2018-03-09 21:37:34 +00:00
final int end = fullSvg.indexOf("\"", idx + 3);
final SvgResult path = fullSvg.substring(idx + 3, end);
2016-01-30 12:20:07 +00:00
2018-03-09 21:37:34 +00:00
if (DotPath.isPathConsistent(path.getSvg()) == false) {
2016-05-19 18:41:37 +00:00
return;
}
2018-03-09 21:37:34 +00:00
dotPath = new DotPath(path);
2016-03-06 16:47:34 +00:00
if (projectionCluster != null) {
// System.err.println("Line::solveLine1 projectionCluster=" + projectionCluster.getClusterPosition());
2016-08-25 20:45:37 +00:00
projectionCluster.manageEntryExitPoint(stringBounder);
2016-03-06 16:47:34 +00:00
// System.err.println("Line::solveLine2 projectionCluster=" + projectionCluster.getClusterPosition());
// if (lhead != null)
// System.err.println("Line::solveLine ltail=" + lhead.getClusterPosition());
// if (ltail != null)
// System.err.println("Line::solveLine ltail=" + ltail.getClusterPosition());
2016-01-09 12:15:40 +00:00
}
2016-03-06 16:47:34 +00:00
dotPath = dotPath.simulateCompound(lhead, ltail);
2011-08-08 17:48:29 +00:00
2018-03-09 21:37:34 +00:00
final SvgResult lineSvg = fullSvg.substring(end);
PointListIterator pointListIterator = lineSvg.getPointsWithThisColor(lineColor);
2011-08-08 17:48:29 +00:00
2015-04-07 18:18:37 +00:00
final LinkType linkType = link.getType();
2016-03-06 16:47:34 +00:00
this.extremity1 = getExtremity(linkType.getDecor2(), pointListIterator, dotPath.getStartPoint(),
2016-12-14 21:01:03 +00:00
dotPath.getStartAngle() + Math.PI, ltail, bibliotekon.getShape(link.getEntity1()));
2016-03-06 16:47:34 +00:00
this.extremity2 = getExtremity(linkType.getDecor1(), pointListIterator, dotPath.getEndPoint(),
2016-12-14 21:01:03 +00:00
dotPath.getEndAngle(), lhead, bibliotekon.getShape(link.getEntity2()));
2016-03-06 16:47:34 +00:00
if (extremity1 instanceof Extremity && extremity2 instanceof Extremity) {
final Point2D p1 = ((Extremity) extremity1).somePoint();
final Point2D p2 = ((Extremity) extremity2).somePoint();
if (p1 != null && p2 != null) {
// http://plantuml.sourceforge.net/qa/?qa=4240/some-relations-point-wrong-direction-when-the-linetype-ortho
final double dist1start = p1.distance(dotPath.getStartPoint());
final double dist1end = p1.distance(dotPath.getEndPoint());
final double dist2start = p2.distance(dotPath.getStartPoint());
final double dist2end = p2.distance(dotPath.getEndPoint());
if (dist1start > dist1end && dist2end > dist2start) {
2018-03-09 21:37:34 +00:00
pointListIterator = lineSvg.getPointsWithThisColor(lineColor);
2016-03-06 16:47:34 +00:00
this.extremity2 = getExtremity(linkType.getDecor1(), pointListIterator, dotPath.getEndPoint(),
2016-12-14 21:01:03 +00:00
dotPath.getEndAngle(), lhead, bibliotekon.getShape(link.getEntity2()));
2016-03-06 16:47:34 +00:00
this.extremity1 = getExtremity(linkType.getDecor2(), pointListIterator, dotPath.getStartPoint(),
2016-12-14 21:01:03 +00:00
dotPath.getStartAngle() + Math.PI, ltail, bibliotekon.getShape(link.getEntity1()));
2016-03-06 16:47:34 +00:00
}
}
}
2011-09-07 20:41:58 +00:00
2015-09-28 20:42:17 +00:00
if (this.labelText != null) {
2018-03-09 21:37:34 +00:00
final Point2D pos = getXY(fullSvg, this.noteLabelColor);
2013-12-10 19:36:50 +00:00
if (pos != null) {
corner1.manage(pos);
2015-09-28 20:42:17 +00:00
this.labelXY = TextBlockUtils.asPositionable(labelText, stringBounder, pos);
2013-12-10 19:36:50 +00:00
}
2011-08-08 17:48:29 +00:00
}
if (this.startTailText != null) {
2018-03-09 21:37:34 +00:00
final Point2D pos = getXY(fullSvg, this.startTailColor);
2013-12-10 19:36:50 +00:00
if (pos != null) {
corner1.manage(pos);
this.startTailLabelXY = TextBlockUtils.asPositionable(startTailText, stringBounder, pos);
}
2011-08-08 17:48:29 +00:00
}
if (this.endHeadText != null) {
2018-03-09 21:37:34 +00:00
final Point2D pos = getXY(fullSvg, this.endHeadColor);
2013-12-10 19:36:50 +00:00
if (pos != null) {
corner1.manage(pos);
this.endHeadLabelXY = TextBlockUtils.asPositionable(endHeadText, stringBounder, pos);
2016-01-09 12:15:40 +00:00
corner1.manage(pos.getX() - 15, pos.getY());
2013-12-10 19:36:50 +00:00
}
2011-08-08 17:48:29 +00:00
}
2011-09-08 10:42:27 +00:00
if (isOpalisable() == false) {
setOpale(false);
}
}
private boolean isOpalisable() {
return dotPath.getBeziers().size() <= 1;
2011-08-08 17:48:29 +00:00
}
2018-03-09 21:37:34 +00:00
private Point2D.Double getXY(SvgResult svgResult, int color) {
final int idx = svgResult.getIndexFromColor(color);
2011-08-08 17:48:29 +00:00
if (idx == -1) {
2013-12-10 19:36:50 +00:00
return null;
2011-08-08 17:48:29 +00:00
}
2018-03-09 21:37:34 +00:00
return SvekUtils.getMinXY(svgResult.substring(idx).extractList(SvgResult.POINTS_EQUALS));
2011-08-08 17:48:29 +00:00
}
2015-04-07 18:18:37 +00:00
public void drawU(UGraphic ug, HtmlColor color) {
2011-09-08 10:42:27 +00:00
if (opale) {
return;
}
2017-04-26 17:48:37 +00:00
ug.draw(new UComment("link " + link.getEntity1().getCode().getFullName() + " to "
+ link.getEntity2().getCode().getFullName()));
2015-04-07 18:18:37 +00:00
double x = 0;
double y = 0;
2013-12-10 19:36:50 +00:00
final Url url = link.getUrl();
if (url != null) {
ug.startUrl(url);
}
if (link.isAutoLinkOfAGroup()) {
final Cluster cl = bibliotekon.getCluster((IGroup) link.getEntity1());
2016-03-06 16:47:34 +00:00
if (cl != null) {
x += cl.getWidth();
x -= dotPath.getStartPoint().getX() - cl.getMinX();
}
2013-12-10 19:36:50 +00:00
}
2011-09-08 10:42:27 +00:00
x += dx;
y += dy;
2011-08-08 17:48:29 +00:00
if (link.isInvis()) {
return;
}
2015-09-28 20:42:17 +00:00
if (this.link.getColors() != null) {
final HtmlColor newColor = this.link.getColors().getColor(ColorType.ARROW, ColorType.LINE);
if (newColor != null) {
color = newColor;
}
} else if (this.link.getSpecificColor() != null) {
2011-08-08 17:48:29 +00:00
color = this.link.getSpecificColor();
}
2011-09-08 10:42:27 +00:00
2013-12-10 19:36:50 +00:00
ug = ug.apply(new UChangeBackColor(null)).apply(new UChangeColor(color));
2015-04-07 18:18:37 +00:00
final LinkType linkType = link.getType();
2017-10-07 09:46:53 +00:00
UStroke stroke = linkType.getStroke3(defaultThickness);
2015-09-28 20:42:17 +00:00
if (link.getColors() != null && link.getColors().getSpecificLineStroke() != null) {
stroke = link.getColors().getSpecificLineStroke();
}
ug = ug.apply(stroke);
2013-12-10 19:36:50 +00:00
double moveEndY = 0;
2015-04-07 18:18:37 +00:00
2016-03-06 16:47:34 +00:00
if (dotPath == null) {
Log.info("DotPath is null for " + this);
return;
}
DotPath todraw = dotPath;
if (link.getEntity2().isGroup() && link.getEntity2().getUSymbol() instanceof USymbolFolder) {
final Cluster endCluster = bibliotekon.getCluster((IGroup) link.getEntity2());
if (endCluster != null) {
final double deltaFolderH = endCluster
.checkFolderPosition(dotPath.getEndPoint(), ug.getStringBounder());
todraw = new DotPath(dotPath);
todraw.moveEndPoint(0, deltaFolderH);
moveEndY = deltaFolderH;
}
2015-04-07 18:18:37 +00:00
}
2013-12-10 19:36:50 +00:00
2017-04-26 17:48:37 +00:00
todraw.setComment(link.getEntity1().getCode().getFullName() + "-" + link.getEntity2().getCode().getFullName());
2016-03-06 16:47:34 +00:00
ug.apply(new UTranslate(x, y)).draw(todraw);
2013-12-10 19:36:50 +00:00
ug = ug.apply(new UStroke()).apply(new UChangeColor(color));
2011-08-08 17:48:29 +00:00
2016-03-06 16:47:34 +00:00
if (this.extremity2 != null) {
2016-12-14 21:01:03 +00:00
UGraphic ug2 = ug;
2015-04-07 18:18:37 +00:00
if (linkType.getDecor1().isFill()) {
2016-12-14 21:01:03 +00:00
ug2 = ug2.apply(new UChangeBackColor(color));
2011-08-08 17:48:29 +00:00
} else {
2016-12-14 21:01:03 +00:00
ug2 = ug2.apply(new UChangeBackColor(null));
2011-08-08 17:48:29 +00:00
}
2016-03-06 16:47:34 +00:00
// System.err.println("Line::draw EXTREMITY1");
2016-12-14 21:01:03 +00:00
this.extremity2.drawU(ug2.apply(new UTranslate(x, y)));
2011-08-08 17:48:29 +00:00
}
2016-03-06 16:47:34 +00:00
if (this.extremity1 != null) {
2016-12-14 21:01:03 +00:00
UGraphic ug2 = ug;
2015-04-07 18:18:37 +00:00
if (linkType.getDecor2().isFill()) {
2016-12-14 21:01:03 +00:00
ug2 = ug2.apply(new UChangeBackColor(color));
2011-08-08 17:48:29 +00:00
} else {
2016-12-14 21:01:03 +00:00
ug2 = ug2.apply(new UChangeBackColor(null));
2011-08-08 17:48:29 +00:00
}
2016-03-06 16:47:34 +00:00
// System.err.println("Line::draw EXTREMITY2");
2016-12-14 21:01:03 +00:00
this.extremity1.drawU(ug2.apply(new UTranslate(x, y)));
2011-08-08 17:48:29 +00:00
}
2016-09-29 19:51:18 +00:00
if (this.labelText != null && this.labelXY != null
&& link.getNoteLinkStrategy() != NoteLinkStrategy.HALF_NOT_PRINTED) {
2015-09-28 20:42:17 +00:00
this.labelText.drawU(ug.apply(new UTranslate(x + this.labelXY.getPosition().getX(), y
+ this.labelXY.getPosition().getY())));
2011-08-08 17:48:29 +00:00
}
2016-11-04 21:39:29 +00:00
if (this.startTailText != null && this.startTailLabelXY != null && this.startTailLabelXY.getPosition() != null) {
2013-12-10 19:36:50 +00:00
this.startTailText.drawU(ug.apply(new UTranslate(x + this.startTailLabelXY.getPosition().getX(), y
+ this.startTailLabelXY.getPosition().getY())));
2011-08-08 17:48:29 +00:00
}
2016-11-04 21:39:29 +00:00
if (this.endHeadText != null && this.endHeadLabelXY != null && this.endHeadLabelXY.getPosition() != null) {
2013-12-10 19:36:50 +00:00
this.endHeadText.drawU(ug.apply(new UTranslate(x + this.endHeadLabelXY.getPosition().getX(), y
+ this.endHeadLabelXY.getPosition().getY())));
}
2015-04-07 18:18:37 +00:00
if (linkType.getMiddleDecor() != LinkMiddleDecor.NONE) {
2013-12-10 19:36:50 +00:00
final PointAndAngle middle = dotPath.getMiddle();
final double angleRad = middle.getAngle();
final double angleDeg = -angleRad * 180.0 / Math.PI;
2017-10-07 09:46:53 +00:00
final UDrawable mi = linkType.getMiddleDecor().getMiddleFactory(arrowLollipopColor)
.createUDrawable(angleDeg - 45);
2013-12-10 19:36:50 +00:00
mi.drawU(ug.apply(new UTranslate(x + middle.getX(), y + middle.getY())));
}
if (url != null) {
ug.closeAction();
2011-08-08 17:48:29 +00:00
}
}
public boolean isInverted() {
return link.isInverted();
}
private double getDecorDzeta() {
2015-04-07 18:18:37 +00:00
final LinkType linkType = link.getType();
final int size1 = linkType.getDecor1().getMargin();
final int size2 = linkType.getDecor2().getMargin();
2011-08-08 17:48:29 +00:00
return size1 + size2;
}
public double getHorizontalDzeta(StringBounder stringBounder) {
2016-07-04 19:06:50 +00:00
if (startUid.equalsId(endUid)) {
2011-08-08 17:48:29 +00:00
return getDecorDzeta();
}
final ArithmeticStrategy strategy;
if (isHorizontal()) {
strategy = new ArithmeticStrategySum();
} else {
return 0;
}
2015-09-28 20:42:17 +00:00
if (labelText != null) {
strategy.eat(labelText.calculateDimension(stringBounder).getWidth());
2011-08-08 17:48:29 +00:00
}
if (startTailText != null) {
strategy.eat(startTailText.calculateDimension(stringBounder).getWidth());
}
if (endHeadText != null) {
strategy.eat(endHeadText.calculateDimension(stringBounder).getWidth());
}
return strategy.getResult() + getDecorDzeta();
}
private boolean isHorizontal() {
return link.getLength() == 1;
}
public double getVerticalDzeta(StringBounder stringBounder) {
2016-07-04 19:06:50 +00:00
if (startUid.equalsId(endUid)) {
2011-08-08 17:48:29 +00:00
return getDecorDzeta();
}
if (isHorizontal()) {
return 0;
}
2013-12-10 19:36:50 +00:00
final ArithmeticStrategy strategy = new ArithmeticStrategySum();
2015-09-28 20:42:17 +00:00
if (labelText != null) {
strategy.eat(labelText.calculateDimension(stringBounder).getHeight());
2011-08-08 17:48:29 +00:00
}
if (startTailText != null) {
strategy.eat(startTailText.calculateDimension(stringBounder).getHeight());
}
if (endHeadText != null) {
strategy.eat(endHeadText.calculateDimension(stringBounder).getHeight());
}
return strategy.getResult() + getDecorDzeta();
}
2013-12-10 19:36:50 +00:00
public void manageCollision(Collection<Shape> allShapes) {
2011-08-08 17:48:29 +00:00
2011-09-07 20:41:58 +00:00
for (Shape sh : allShapes) {
final Positionable cl = PositionableUtils.addMargin(sh, 8, 8);
2013-12-10 19:36:50 +00:00
if (startTailText != null && startTailLabelXY != null && PositionableUtils.intersect(cl, startTailLabelXY)) {
2011-09-07 20:41:58 +00:00
startTailLabelXY = PositionableUtils.moveAwayFrom(cl, startTailLabelXY);
2011-08-08 17:48:29 +00:00
}
2013-12-10 19:36:50 +00:00
if (endHeadText != null && endHeadLabelXY != null && PositionableUtils.intersect(cl, endHeadLabelXY)) {
2011-09-07 20:41:58 +00:00
endHeadLabelXY = PositionableUtils.moveAwayFrom(cl, endHeadLabelXY);
2011-08-08 17:48:29 +00:00
}
2011-09-07 20:41:58 +00:00
}
2011-08-08 17:48:29 +00:00
2011-09-07 20:41:58 +00:00
// final Positionable start = getStartTailPositionnable();
// if (start != null) {
// for (Shape sh : allShapes) {
// if (cut(start, sh)) {
// avoid(startTailLabelXY, start, sh);
// }
// }
// }
//
// final Positionable end = getEndHeadPositionnable();
// if (end != null) {
// for (Shape sh : allShapes) {
// if (cut(end, sh)) {
// avoid(endHeadLabelXY, end, sh);
// }
// }
// }
2011-08-08 17:48:29 +00:00
}
private void avoid(Point2D.Double move, Positionable pos, Shape sh) {
final Oscillator oscillator = new Oscillator();
final Point2D.Double orig = new Point2D.Double(move.x, move.y);
while (cut(pos, sh)) {
final Point2D.Double m = oscillator.nextPosition();
move.setLocation(orig.x + m.x, orig.y + m.y);
}
}
private boolean cut(Positionable pos, Shape sh) {
return BezierUtils.intersect(pos, sh) || tooClose(pos);
}
private boolean tooClose(Positionable pos) {
final double dist = dotPath.getMinDist(BezierUtils.getCenter(pos));
final Dimension2D dim = pos.getSize();
2013-12-10 19:36:50 +00:00
// Log.println("dist=" + dist);
2011-08-08 17:48:29 +00:00
return dist < (dim.getWidth() / 2 + 2) || dist < (dim.getHeight() / 2 + 2);
}
2011-09-08 10:42:27 +00:00
public void moveSvek(double deltaX, double deltaY) {
this.dx += deltaX;
this.dy += deltaY;
}
public final DotPath getDotPath() {
final DotPath result = new DotPath(dotPath);
result.moveSvek(dx, dy);
return result;
}
public int getLength() {
return link.getLength();
}
public void setOpale(boolean opale) {
this.link.setOpale(opale);
this.opale = opale;
}
public boolean isOpale() {
return opale;
}
2013-12-10 19:36:50 +00:00
public boolean isHorizontalSolitary() {
return link.isHorizontalSolitary();
}
2015-04-07 18:18:37 +00:00
public boolean isLinkFromOrTo(IEntity group) {
2013-12-10 19:36:50 +00:00
return link.getEntity1() == group || link.getEntity2() == group;
}
public boolean hasEntryPoint() {
return link.hasEntryPoint();
}
public void setProjectionCluster(Cluster cluster) {
this.projectionCluster = cluster;
}
public boolean isHidden() {
return link.isHidden();
}
public boolean sameConnections(Line other) {
return link.sameConnections(other.link);
}
private boolean isAutolink() {
return link.getEntity1() == link.getEntity2();
}
2011-09-08 10:42:27 +00:00
2015-04-07 18:18:37 +00:00
public Point2D getMyPoint(IEntity entity) {
if (link.getEntity1() == entity) {
return moveDelta(dotPath.getStartPoint());
}
if (link.getEntity2() == entity) {
return moveDelta(dotPath.getEndPoint());
}
throw new IllegalArgumentException();
}
private Point2D moveDelta(Point2D pt) {
return new Point2D.Double(pt.getX() + dx, pt.getY() + dy);
}
public boolean isLink(Link link) {
return this.link == link;
}
public Point2D getStartContactPoint() {
final Point2D start = dotPath.getStartPoint();
if (start == null) {
return null;
}
return new Point2D.Double(dx + start.getX(), dy + start.getY());
}
public Point2D getEndContactPoint() {
final Point2D end = dotPath.getEndPoint();
if (end == null) {
return null;
}
return new Point2D.Double(dx + end.getX(), dy + end.getY());
}
2015-05-31 18:56:03 +00:00
public IEntity getOther(IEntity entity) {
if (link.contains(entity)) {
return link.getOther(entity);
}
return null;
}
2011-08-08 17:48:29 +00:00
}