2016-03-06 16:47:34 +00:00
|
|
|
/* ========================================================================
|
|
|
|
* PlantUML : a free UML diagram generator
|
|
|
|
* ========================================================================
|
|
|
|
*
|
2022-03-07 19:33:46 +00:00
|
|
|
* (C) Copyright 2009-2023, Arnaud Roques
|
2016-03-06 16:47:34 +00:00
|
|
|
*
|
|
|
|
* Project Info: http://plantuml.com
|
|
|
|
*
|
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
|
|
|
|
*
|
2016-03-06 16:47:34 +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
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Original Author: Arnaud Roques
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
2020-12-21 19:05:24 +00:00
|
|
|
package net.sourceforge.plantuml.sdot;
|
2016-03-06 16:47:34 +00:00
|
|
|
|
2020-04-19 16:04:39 +00:00
|
|
|
import java.awt.geom.Point2D;
|
|
|
|
|
2018-10-21 19:44:14 +00:00
|
|
|
import h.ST_Agedge_s;
|
|
|
|
import h.ST_Agedgeinfo_t;
|
|
|
|
import h.ST_bezier;
|
|
|
|
import h.ST_pointf;
|
|
|
|
import h.ST_splines;
|
2019-03-29 22:14:07 +00:00
|
|
|
import h.ST_textlabel_t;
|
2016-03-06 16:47:34 +00:00
|
|
|
import net.sourceforge.plantuml.ColorParam;
|
2020-10-12 20:56:58 +00:00
|
|
|
import net.sourceforge.plantuml.LineParam;
|
2016-03-06 16:47:34 +00:00
|
|
|
import net.sourceforge.plantuml.UmlDiagramType;
|
2021-11-01 07:00:05 +00:00
|
|
|
import net.sourceforge.plantuml.UseStyle;
|
2016-03-06 16:47:34 +00:00
|
|
|
import net.sourceforge.plantuml.cucadiagram.CucaDiagram;
|
|
|
|
import net.sourceforge.plantuml.cucadiagram.Link;
|
2020-10-12 20:56:58 +00:00
|
|
|
import net.sourceforge.plantuml.cucadiagram.LinkType;
|
2016-03-06 16:47:34 +00:00
|
|
|
import net.sourceforge.plantuml.graphic.TextBlock;
|
|
|
|
import net.sourceforge.plantuml.graphic.UDrawable;
|
|
|
|
import net.sourceforge.plantuml.graphic.color.ColorType;
|
|
|
|
import net.sourceforge.plantuml.posimo.DotPath;
|
|
|
|
import net.sourceforge.plantuml.skin.rose.Rose;
|
2021-11-01 07:00:05 +00:00
|
|
|
import net.sourceforge.plantuml.style.PName;
|
|
|
|
import net.sourceforge.plantuml.style.SName;
|
2022-03-01 18:11:51 +00:00
|
|
|
import net.sourceforge.plantuml.style.StyleSignatureBasic;
|
2020-10-12 20:56:58 +00:00
|
|
|
import net.sourceforge.plantuml.svek.extremity.ExtremityFactory;
|
2016-03-06 16:47:34 +00:00
|
|
|
import net.sourceforge.plantuml.ugraphic.UEllipse;
|
|
|
|
import net.sourceforge.plantuml.ugraphic.UGraphic;
|
|
|
|
import net.sourceforge.plantuml.ugraphic.URectangle;
|
2020-10-12 20:56:58 +00:00
|
|
|
import net.sourceforge.plantuml.ugraphic.UStroke;
|
2016-03-06 16:47:34 +00:00
|
|
|
import net.sourceforge.plantuml.ugraphic.UTranslate;
|
2020-03-18 10:50:02 +00:00
|
|
|
import net.sourceforge.plantuml.ugraphic.color.HColor;
|
2020-04-19 16:04:39 +00:00
|
|
|
import net.sourceforge.plantuml.ugraphic.color.HColorNone;
|
2020-03-18 10:50:02 +00:00
|
|
|
import net.sourceforge.plantuml.ugraphic.color.HColorUtils;
|
2016-03-06 16:47:34 +00:00
|
|
|
import smetana.core.Macro;
|
|
|
|
|
2020-12-21 19:05:24 +00:00
|
|
|
public class SmetanaPath implements UDrawable {
|
2016-03-06 16:47:34 +00:00
|
|
|
|
|
|
|
private final Link link;
|
2018-10-21 19:44:14 +00:00
|
|
|
private final ST_Agedge_s edge;
|
2016-03-06 16:47:34 +00:00
|
|
|
private final YMirror ymirror;
|
|
|
|
private final CucaDiagram diagram;
|
|
|
|
private final TextBlock label;
|
2018-10-21 19:44:14 +00:00
|
|
|
private final TextBlock headLabel;
|
|
|
|
private final TextBlock tailLabel;
|
2016-03-06 16:47:34 +00:00
|
|
|
private final Rose rose = new Rose();
|
|
|
|
|
2020-12-21 19:05:24 +00:00
|
|
|
public SmetanaPath(Link link, ST_Agedge_s edge, YMirror ymirror, CucaDiagram diagram, TextBlock label,
|
2018-11-26 18:46:22 +00:00
|
|
|
TextBlock tailLabel, TextBlock headLabel) {
|
2016-03-06 16:47:34 +00:00
|
|
|
this.link = link;
|
|
|
|
this.edge = edge;
|
|
|
|
this.ymirror = ymirror;
|
|
|
|
this.diagram = diagram;
|
|
|
|
this.label = label;
|
2018-10-21 19:44:14 +00:00
|
|
|
this.tailLabel = tailLabel;
|
|
|
|
this.headLabel = headLabel;
|
2016-03-06 16:47:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private ColorParam getArrowColorParam() {
|
|
|
|
if (diagram.getUmlDiagramType() == UmlDiagramType.CLASS) {
|
2017-02-15 21:34:36 +00:00
|
|
|
return ColorParam.arrow;
|
2016-03-06 16:47:34 +00:00
|
|
|
} else if (diagram.getUmlDiagramType() == UmlDiagramType.OBJECT) {
|
2017-02-15 21:34:36 +00:00
|
|
|
return ColorParam.arrow;
|
2016-03-06 16:47:34 +00:00
|
|
|
} else if (diagram.getUmlDiagramType() == UmlDiagramType.DESCRIPTION) {
|
2017-02-15 21:34:36 +00:00
|
|
|
return ColorParam.arrow;
|
2016-03-06 16:47:34 +00:00
|
|
|
} else if (diagram.getUmlDiagramType() == UmlDiagramType.ACTIVITY) {
|
2017-02-15 21:34:36 +00:00
|
|
|
return ColorParam.arrow;
|
2016-03-06 16:47:34 +00:00
|
|
|
} else if (diagram.getUmlDiagramType() == UmlDiagramType.STATE) {
|
2017-02-15 21:34:36 +00:00
|
|
|
return ColorParam.arrow;
|
2016-03-06 16:47:34 +00:00
|
|
|
}
|
|
|
|
throw new IllegalStateException();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void drawU(UGraphic ug) {
|
|
|
|
|
2020-12-21 19:05:24 +00:00
|
|
|
if (link.isHidden()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-11-01 07:00:05 +00:00
|
|
|
HColor color;
|
|
|
|
|
|
|
|
if (UseStyle.useBetaStyle()) {
|
2022-03-01 18:11:51 +00:00
|
|
|
color = StyleSignatureBasic.of(SName.root, SName.element, diagram.getUmlDiagramType().getStyleName(), SName.arrow)
|
2021-11-01 07:00:05 +00:00
|
|
|
.getMergedStyle(diagram.getSkinParam().getCurrentStyleBuilder())
|
|
|
|
.value(PName.LineColor)
|
|
|
|
.asColor(diagram.getSkinParam().getThemeStyle(), diagram.getSkinParam().getIHtmlColorSet());
|
|
|
|
} else {
|
|
|
|
color = rose.getHtmlColor(diagram.getSkinParam(), null, getArrowColorParam());
|
|
|
|
}
|
2016-03-06 16:47:34 +00:00
|
|
|
|
|
|
|
if (this.link.getColors() != null) {
|
2020-03-18 10:50:02 +00:00
|
|
|
final HColor newColor = this.link.getColors().getColor(ColorType.ARROW, ColorType.LINE);
|
2016-03-06 16:47:34 +00:00
|
|
|
if (newColor != null) {
|
|
|
|
color = newColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (this.link.getSpecificColor() != null) {
|
|
|
|
color = this.link.getSpecificColor();
|
|
|
|
}
|
|
|
|
|
|
|
|
DotPath dotPath = getDotPath(edge);
|
2017-07-03 17:59:53 +00:00
|
|
|
if (ymirror != null && dotPath != null) {
|
2016-03-06 16:47:34 +00:00
|
|
|
dotPath = ymirror.getMirrored(dotPath);
|
|
|
|
}
|
|
|
|
|
2017-07-03 17:59:53 +00:00
|
|
|
if (dotPath != null) {
|
2020-10-12 20:56:58 +00:00
|
|
|
final LinkType linkType = link.getType();
|
|
|
|
UStroke stroke = linkType.getStroke3(diagram.getSkinParam().getThickness(LineParam.arrow, null));
|
|
|
|
if (link.getColors() != null && link.getColors().getSpecificLineStroke() != null) {
|
|
|
|
stroke = link.getColors().getSpecificLineStroke();
|
|
|
|
}
|
|
|
|
|
|
|
|
ug.apply(stroke).apply(color).draw(dotPath);
|
|
|
|
printExtremityAtStart(ug.apply(color));
|
|
|
|
printExtremityAtEnd(ug.apply(color));
|
2017-07-03 17:59:53 +00:00
|
|
|
}
|
2018-10-21 19:44:14 +00:00
|
|
|
if (getLabelRectangleTranslate("label") != null) {
|
|
|
|
label.drawU(ug.apply(getLabelRectangleTranslate("label")));
|
|
|
|
}
|
|
|
|
if (getLabelRectangleTranslate("head_label") != null) {
|
|
|
|
headLabel.drawU(ug.apply(getLabelRectangleTranslate("head_label")));
|
|
|
|
}
|
|
|
|
if (getLabelRectangleTranslate("tail_label") != null) {
|
|
|
|
tailLabel.drawU(ug.apply(getLabelRectangleTranslate("tail_label")));
|
2016-03-06 16:47:34 +00:00
|
|
|
}
|
|
|
|
// printDebug(ug);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-10-12 20:56:58 +00:00
|
|
|
private void printExtremityAtStart(UGraphic ug) {
|
|
|
|
final ExtremityFactory extremityFactory2 = link.getType().getDecor2()
|
2021-11-08 13:56:52 +00:00
|
|
|
.getExtremityFactoryComplete(diagram.getSkinParam().getBackgroundColor());
|
2020-10-12 20:56:58 +00:00
|
|
|
if (extremityFactory2 == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
final ST_splines splines = getSplines(edge);
|
|
|
|
DotPath s = getDotPath(splines);
|
|
|
|
Point2D p0 = s.getStartPoint();
|
|
|
|
double startAngle = s.getStartAngle();
|
|
|
|
if (ymirror != null) {
|
|
|
|
p0 = ymirror.getMirrored(p0);
|
|
|
|
startAngle = -startAngle + Math.PI;
|
|
|
|
}
|
2020-11-21 17:33:24 +00:00
|
|
|
try {
|
|
|
|
final UDrawable extremity2 = extremityFactory2.createUDrawable(p0, startAngle, null);
|
|
|
|
if (extremity2 != null) {
|
|
|
|
extremity2.drawU(ug);
|
|
|
|
}
|
|
|
|
} catch (UnsupportedOperationException e) {
|
|
|
|
System.err.println("CANNOT DRAW printExtremityAtStart");
|
2020-10-12 20:56:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void printExtremityAtEnd(UGraphic ug) {
|
|
|
|
final ExtremityFactory extremityFactory1 = link.getType().getDecor1()
|
2021-11-08 13:56:52 +00:00
|
|
|
.getExtremityFactoryComplete(diagram.getSkinParam().getBackgroundColor());
|
2020-10-12 20:56:58 +00:00
|
|
|
if (extremityFactory1 == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
final ST_splines splines = getSplines(edge);
|
|
|
|
DotPath s = getDotPath(splines);
|
|
|
|
Point2D p0 = s.getEndPoint();
|
|
|
|
double endAngle = s.getEndAngle();
|
|
|
|
if (ymirror != null) {
|
|
|
|
p0 = ymirror.getMirrored(p0);
|
|
|
|
endAngle = -endAngle;
|
|
|
|
}
|
2020-11-21 17:33:24 +00:00
|
|
|
try {
|
|
|
|
final UDrawable extremity1 = extremityFactory1.createUDrawable(p0, endAngle, null);
|
|
|
|
if (extremity1 != null) {
|
|
|
|
extremity1.drawU(ug);
|
|
|
|
}
|
|
|
|
} catch (UnsupportedOperationException e) {
|
|
|
|
System.err.println("CANNOT DRAW printExtremityAtEnd");
|
2020-10-12 20:56:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-06 16:47:34 +00:00
|
|
|
private void printDebug(UGraphic ug) {
|
2020-04-19 16:04:39 +00:00
|
|
|
ug = ug.apply(HColorUtils.BLUE).apply(HColorUtils.BLUE.bg());
|
2018-10-21 19:44:14 +00:00
|
|
|
final ST_splines splines = getSplines(edge);
|
2020-11-21 17:33:24 +00:00
|
|
|
final ST_bezier beziers = splines.list.get__(0);
|
2018-10-21 19:44:14 +00:00
|
|
|
for (int i = 0; i < beziers.size; i++) {
|
2016-03-06 16:47:34 +00:00
|
|
|
Point2D pt = getPoint(splines, i);
|
|
|
|
if (ymirror != null) {
|
|
|
|
pt = ymirror.getMirrored(pt);
|
|
|
|
}
|
|
|
|
ug.apply(new UTranslate(pt).compose(new UTranslate(-1, -1))).draw(new UEllipse(3, 3));
|
|
|
|
}
|
2018-10-21 19:44:14 +00:00
|
|
|
if (getLabelRectangleTranslate("label") != null && getLabelURectangle() != null) {
|
2020-04-19 16:04:39 +00:00
|
|
|
ug = ug.apply(HColorUtils.BLUE).apply(new HColorNone().bg());
|
2018-10-21 19:44:14 +00:00
|
|
|
ug.apply(getLabelRectangleTranslate("label")).draw(getLabelURectangle());
|
2016-03-06 16:47:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private URectangle getLabelURectangle() {
|
2018-10-21 19:44:14 +00:00
|
|
|
final ST_Agedgeinfo_t data = (ST_Agedgeinfo_t) Macro.AGDATA(edge).castTo(ST_Agedgeinfo_t.class);
|
|
|
|
ST_textlabel_t label = (ST_textlabel_t) data.label;
|
2016-03-06 16:47:34 +00:00
|
|
|
if (label == null) {
|
|
|
|
return null;
|
|
|
|
}
|
2018-10-21 19:44:14 +00:00
|
|
|
final ST_pointf dimen = (ST_pointf) label.dimen;
|
2018-11-26 18:46:22 +00:00
|
|
|
final ST_pointf space = (ST_pointf) label.space;
|
|
|
|
final ST_pointf pos = (ST_pointf) label.pos;
|
|
|
|
final double x = pos.x;
|
|
|
|
final double y = pos.y;
|
|
|
|
final double width = dimen.x;
|
|
|
|
final double height = dimen.y;
|
2016-03-06 16:47:34 +00:00
|
|
|
return new URectangle(width, height);
|
|
|
|
}
|
|
|
|
|
2018-10-21 19:44:14 +00:00
|
|
|
private UTranslate getLabelRectangleTranslate(String fieldName) {
|
2018-11-26 18:46:22 +00:00
|
|
|
// final String fieldName = "label";
|
2020-12-01 21:39:27 +00:00
|
|
|
final ST_Agedgeinfo_t data = (ST_Agedgeinfo_t) Macro.AGDATA(edge);
|
2018-11-26 18:46:22 +00:00
|
|
|
ST_textlabel_t label = null;
|
|
|
|
if (fieldName.equals("label")) {
|
|
|
|
label = data.label;
|
|
|
|
} else if (fieldName.equals("head_label")) {
|
|
|
|
label = data.head_label;
|
|
|
|
} else if (fieldName.equals("tail_label")) {
|
|
|
|
label = data.tail_label;
|
|
|
|
}
|
2016-03-06 16:47:34 +00:00
|
|
|
if (label == null) {
|
|
|
|
return null;
|
|
|
|
}
|
2018-11-26 18:46:22 +00:00
|
|
|
final ST_pointf dimen = (ST_pointf) label.dimen;
|
|
|
|
final ST_pointf space = (ST_pointf) label.space;
|
|
|
|
final ST_pointf pos = (ST_pointf) label.pos;
|
|
|
|
final double x = pos.x;
|
|
|
|
final double y = pos.y;
|
|
|
|
final double width = dimen.x;
|
|
|
|
final double height = dimen.y;
|
2016-03-06 16:47:34 +00:00
|
|
|
|
|
|
|
if (ymirror == null) {
|
|
|
|
return new UTranslate(x - width / 2, y - height / 2);
|
|
|
|
}
|
|
|
|
return ymirror.getMirrored(new UTranslate(x - width / 2, y + height / 2));
|
|
|
|
}
|
|
|
|
|
2018-10-21 19:44:14 +00:00
|
|
|
public DotPath getDotPath(ST_Agedge_s e) {
|
|
|
|
final ST_splines splines = getSplines(e);
|
2016-03-06 16:47:34 +00:00
|
|
|
return getDotPath(splines);
|
|
|
|
}
|
|
|
|
|
2018-10-21 19:44:14 +00:00
|
|
|
private ST_splines getSplines(ST_Agedge_s e) {
|
2020-12-01 21:39:27 +00:00
|
|
|
final ST_Agedgeinfo_t data = (ST_Agedgeinfo_t) Macro.AGDATA(e);
|
2018-10-21 19:44:14 +00:00
|
|
|
final ST_splines splines = (ST_splines) data.spl;
|
2016-03-06 16:47:34 +00:00
|
|
|
return splines;
|
|
|
|
}
|
|
|
|
|
2018-10-21 19:44:14 +00:00
|
|
|
private DotPath getDotPath(ST_splines splines) {
|
2017-07-03 17:59:53 +00:00
|
|
|
if (splines == null) {
|
|
|
|
System.err.println("ERROR, no splines for getDotPath");
|
|
|
|
return null;
|
|
|
|
}
|
2016-03-06 16:47:34 +00:00
|
|
|
DotPath result = new DotPath();
|
2020-11-21 17:33:24 +00:00
|
|
|
final ST_bezier beziers = (ST_bezier) splines.list.get__(0);
|
2016-03-06 16:47:34 +00:00
|
|
|
final Point2D pt1 = getPoint(splines, 0);
|
|
|
|
final Point2D pt2 = getPoint(splines, 1);
|
|
|
|
final Point2D pt3 = getPoint(splines, 2);
|
|
|
|
final Point2D pt4 = getPoint(splines, 3);
|
|
|
|
result = result.addCurve(pt1, pt2, pt3, pt4);
|
2018-10-21 19:44:14 +00:00
|
|
|
final int n = beziers.size;
|
2016-03-06 16:47:34 +00:00
|
|
|
for (int i = 4; i < n; i += 3) {
|
|
|
|
final Point2D ppt2 = getPoint(splines, i);
|
|
|
|
final Point2D ppt3 = getPoint(splines, i + 1);
|
|
|
|
final Point2D ppt4 = getPoint(splines, i + 2);
|
|
|
|
result = result.addCurve(ppt2, ppt3, ppt4);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-10-21 19:44:14 +00:00
|
|
|
private Point2D getPoint(ST_splines splines, int i) {
|
2020-11-21 17:33:24 +00:00
|
|
|
final ST_bezier beziers = (ST_bezier) splines.list.get__(0);
|
|
|
|
final ST_pointf pt = beziers.list.get__(i);
|
2018-11-26 18:46:22 +00:00
|
|
|
return new Point2D.Double(pt.x, pt.y);
|
2016-03-06 16:47:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|