1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-11-22 04:55:10 +00:00
This commit is contained in:
Arnaud Roques 2023-07-25 18:52:47 +02:00
parent 1b58f96369
commit a327d636a7
14 changed files with 231 additions and 70 deletions

View File

@ -95,6 +95,11 @@ public class Link extends WithLinkType implements Hideable, Removeable {
private Url url;
public LinkStrategy getLinkStrategy() {
return LinkStrategy.LEGACY;
// return LinkStrategy.SIMPLIER;
}
public String idCommentForSvg() {
if (type.looksLikeRevertedForSvg())
return getEntity1().getName() + "-backto-" + getEntity2().getName();
@ -542,7 +547,7 @@ public class Link extends WithLinkType implements Hideable, Removeable {
}
public final boolean hasKal1() {
return this.linkArg.getKal1() != null && !this.linkArg.getKal1().isEmpty();
return this.linkArg.getKal1() != null && !this.linkArg.getKal1().isEmpty();
}
public final boolean hasKal2() {

View File

@ -0,0 +1,58 @@
/* ========================================================================
* 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/paypal
*
* 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
*
*
*/
package net.sourceforge.plantuml.abel;
public enum LinkStrategy {
// Temporary class, while we are fixing
// https://github.com/plantuml/plantuml/issues/1491
/*
* In legacy mode, we are drawing arrow tail and arrow head in GraphViz
* generated dot. (see LinkType::getSpecificDecorationSvek).
* We then retrieve tail/head in generated SVG to compute link decoration angle.
*
* Drawbacks: sometimes, GraphViz does NOT draw those decorations, which causes issues
*/
LEGACY,
/*
* In simplier mode, there are no tail/head in GraphViz generated dot.
* The decoration angle is retrieve using Bezier data.
*
*/
SIMPLIER
}

View File

@ -57,6 +57,7 @@ public class FtileIfNude extends FtileDimensionMemoize {
protected double xDeltaNote = 0;
protected double yDeltaNote = 0;
protected double suppWidthNode = 0;
FtileIfNude(Ftile tile1, Ftile tile2, Swimlane in) {
super(tile1.skinParam());
@ -103,7 +104,7 @@ public class FtileIfNude extends FtileDimensionMemoize {
final XDimension2D dimTotal = calculateDimensionInternal(stringBounder);
final XDimension2D dim2 = tile2.calculateDimension(stringBounder);
final double x2 = dimTotal.getWidth() - dim2.getWidth();
final double x2 = dimTotal.getWidth() - dim2.getWidth() - suppWidthNode;
final double y2 = yDeltaNote;
return new UTranslate(x2, y2);
@ -143,7 +144,8 @@ public class FtileIfNude extends FtileDimensionMemoize {
final FtileGeometry dim2 = tile2.calculateDimension(stringBounder);
final double innerMargin = widthInner(stringBounder);
final double width = xDeltaNote + dim1.getLeft() + innerMargin + (dim2.getWidth() - dim2.getLeft());
final double width = xDeltaNote + dim1.getLeft() + innerMargin + (dim2.getWidth() - dim2.getLeft())
+ suppWidthNode;
final XDimension2D dim12 = dim1.mergeLR(dim2);

View File

@ -56,6 +56,7 @@ import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment;
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
import net.sourceforge.plantuml.klimt.shape.TextBlock;
import net.sourceforge.plantuml.klimt.shape.TextBlockUtils;
import net.sourceforge.plantuml.sequencediagram.NotePosition;
import net.sourceforge.plantuml.skin.AlignmentParam;
import net.sourceforge.plantuml.style.ISkinParam;
import net.sourceforge.plantuml.style.PName;
@ -69,26 +70,40 @@ public class FtileIfWithDiamonds extends FtileIfNude {
private static final double SUPP_WIDTH = 20;
protected final Ftile diamond1;
protected final Ftile diamond2;
final private TextBlock opale;
private TextBlock opaleLeft = TextBlockUtils.EMPTY_TEXT_BLOCK;
private TextBlock opaleRight = TextBlockUtils.EMPTY_TEXT_BLOCK;
public FtileIfWithDiamonds(Ftile diamond1, Ftile tile1, Ftile tile2, Ftile diamond2, Swimlane in,
StringBounder stringBounder, Collection<PositionedNote> notes) {
super(tile1, tile2, in);
this.diamond1 = diamond1;
this.diamond2 = diamond2;
if (notes.size() == 1) {
final PositionedNote first = notes.iterator().next();
this.opale = createOpale(first, skinParam());
final double pos1 = getTranslateDiamond1(stringBounder).getDx();
final XDimension2D dimOpale = opale.calculateDimension(stringBounder);
final double opaleWith = dimOpale.getWidth();
if (opaleWith > pos1)
xDeltaNote = opaleWith - pos1;
for (PositionedNote first : notes) {
if (first.getNotePosition() == NotePosition.LEFT) {
if (this.opaleLeft != TextBlockUtils.EMPTY_TEXT_BLOCK)
continue;
this.opaleLeft = createOpale(first, skinParam());
final double pos1 = getTranslateDiamond1(stringBounder).getDx();
final XDimension2D dimOpale = opaleLeft.calculateDimension(stringBounder);
final double opaleWith = dimOpale.getWidth();
if (opaleWith > pos1)
xDeltaNote = opaleWith - pos1;
yDeltaNote = dimOpale.getHeight();
yDeltaNote = Math.max(yDeltaNote, dimOpale.getHeight());
} else if (first.getNotePosition() == NotePosition.RIGHT) {
if (this.opaleRight != TextBlockUtils.EMPTY_TEXT_BLOCK)
continue;
this.opaleRight = createOpale(first, skinParam());
final XDimension2D dimOpale = opaleRight.calculateDimension(stringBounder);
final double pos1 = getTranslateDiamond1(stringBounder).getDx()
+ diamond1.calculateDimension(stringBounder).getWidth() + dimOpale.getWidth();
final double pos2 = calculateDimensionInternalSlow(stringBounder).getWidth();
if (pos1 > pos2)
suppWidthNode = pos1 - pos2;
yDeltaNote = Math.max(yDeltaNote, dimOpale.getHeight());
}
clearCacheDimensionInternal();
} else {
this.opale = TextBlockUtils.EMPTY_TEXT_BLOCK;
}
}
@ -167,10 +182,16 @@ public class FtileIfWithDiamonds extends FtileIfNude {
public void drawU(UGraphic ug) {
final StringBounder stringBounder = ug.getStringBounder();
if (TextBlockUtils.isEmpty(opale, stringBounder) == false) {
if (TextBlockUtils.isEmpty(opaleLeft, stringBounder) == false) {
final double xOpale = getTranslateDiamond1(stringBounder).getDx()
- opale.calculateDimension(stringBounder).getWidth();
opale.drawU(ug.apply(UTranslate.dx(xOpale)));
- opaleLeft.calculateDimension(stringBounder).getWidth();
opaleLeft.drawU(ug.apply(UTranslate.dx(xOpale)));
}
if (TextBlockUtils.isEmpty(opaleRight, stringBounder) == false) {
final double xOpale = getTranslateDiamond1(stringBounder).getDx()
+ diamond1.calculateDimension(stringBounder).getWidth();
opaleRight.drawU(ug.apply(UTranslate.dx(xOpale)));
}
ug.apply(getTranslateDiamond1(stringBounder)).draw(diamond1);

View File

@ -37,6 +37,7 @@
package net.sourceforge.plantuml.decoration;
import net.sourceforge.plantuml.OptionFlags;
import net.sourceforge.plantuml.abel.LinkStrategy;
import net.sourceforge.plantuml.klimt.color.HColor;
import net.sourceforge.plantuml.svek.extremity.ExtremityFactory;
import net.sourceforge.plantuml.svek.extremity.ExtremityFactoryArrow;
@ -102,13 +103,13 @@ public enum LinkDecor {
}
public ExtremityFactory getExtremityFactoryComplete(HColor backgroundColor) {
if (this == EXTENDS) {
if (this == EXTENDS)
return new ExtremityFactoryTriangle(backgroundColor, 16, 6);
}
return getExtremityFactory(backgroundColor);
return getExtremityFactoryLegacy(backgroundColor);
}
public ExtremityFactory getExtremityFactory(HColor backgroundColor) {
public ExtremityFactory getExtremityFactoryLegacy(HColor backgroundColor) {
switch (this) {
case PLUS:
return new ExtremityFactoryPlus(backgroundColor);

View File

@ -38,6 +38,7 @@ package net.sourceforge.plantuml.decoration;
import java.util.Objects;
import net.sourceforge.plantuml.abel.LinkStrategy;
import net.sourceforge.plantuml.klimt.UStroke;
public class LinkType {
@ -151,7 +152,11 @@ public class LinkType {
return new LinkType(decor1, decor2, middleDecor, LinkStyle.INVISIBLE());
}
public String getSpecificDecorationSvek() {
public String getSpecificDecorationSvek(LinkStrategy linkStrategy) {
if (linkStrategy == LinkStrategy.SIMPLIER)
return "arrowtail=none,arrowhead=none";
final StringBuilder sb = new StringBuilder();
final boolean isEmpty1 = decor1 == LinkDecor.NONE;

View File

@ -175,7 +175,7 @@ public class ElkPath implements UDrawable {
if (decors == LinkDecor.EXTENDS)
return new ExtremityFactoryExtends(backColor).createUDrawable(new XPoint2D(0, 0), angle, null);
final ExtremityFactory extremityFactory = decors.getExtremityFactory(backColor);
final ExtremityFactory extremityFactory = decors.getExtremityFactoryLegacy(backColor);
if (extremityFactory == null)
return null;

View File

@ -35,7 +35,8 @@
*/
package net.sourceforge.plantuml.klimt;
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
import java.awt.geom.AffineTransform;
import net.sourceforge.plantuml.klimt.geom.XPoint2D;
import net.sourceforge.plantuml.klimt.geom.XRectangle2D;
@ -116,4 +117,10 @@ public class UTranslate implements UChange {
return new XPoint2D(dx, dy);
}
public UTranslate rotate(double angle) {
final AffineTransform rotate = AffineTransform.getRotateInstance(angle);
return UTranslate.point(new XPoint2D(dx, dy).transform(rotate));
}
}

View File

@ -50,6 +50,7 @@ import net.sourceforge.plantuml.abel.Hideable;
import net.sourceforge.plantuml.abel.LeafType;
import net.sourceforge.plantuml.abel.Link;
import net.sourceforge.plantuml.abel.LinkArrow;
import net.sourceforge.plantuml.abel.LinkStrategy;
import net.sourceforge.plantuml.abel.NoteLinkStrategy;
import net.sourceforge.plantuml.cucadiagram.EntityPort;
import net.sourceforge.plantuml.decoration.LinkDecor;
@ -164,6 +165,10 @@ public class SvekLine implements Moveable, Hideable, GuideLine {
return super.toString() + " color=" + lineColor;
}
public LinkStrategy getLinkStrategy() {
return link.getLinkStrategy();
}
public Direction getArrowDirection() {
if (getLinkArrow() == LinkArrow.BACKWARD)
return getArrowDirectionInternal().getInv();
@ -377,7 +382,7 @@ public class SvekLine implements Moveable, Hideable, GuideLine {
// }
sb.append("[");
final LinkType linkType = link.getTypePatchCluster();
String decoration = linkType.getSpecificDecorationSvek();
String decoration = linkType.getSpecificDecorationSvek(getLinkStrategy());
if (decoration.length() > 0 && decoration.endsWith(",") == false)
decoration += ",";
@ -490,15 +495,36 @@ public class SvekLine implements Moveable, Hideable, GuideLine {
return endUid.getPrefix();
}
private UDrawable getExtremitySpecial(final XPoint2D center, LinkDecor decor, double angle, Cluster cluster,
private UDrawable getExtremitySpecial(XPoint2D center, LinkDecor decor, double angle, Cluster cluster,
SvekNode nodeContact) {
final ExtremityFactory extremityFactory = decor.getExtremityFactory(backgroundColor);
final ExtremityFactory extremityFactory = decor.getExtremityFactoryLegacy(backgroundColor);
return extremityFactory.createUDrawable(center, angle, null);
}
private UDrawable getExtremitySimplier(XPoint2D center, ExtremityFactory extremityFactory, double angle,
Cluster cluster, SvekNode nodeContact, boolean isStart) {
System.err.println("extremityFactory=" + extremityFactory + " " + isStart);
if (extremityFactory == null)
return null;
Side side = null;
if (nodeContact != null)
side = nodeContact.getRectangleArea().getClosestSide(center);
final Extremity extremity = (Extremity) extremityFactory.createUDrawable(center, angle, null);
final double decorationLength = extremity.getDecorationLength();
System.err.println("decorationLength=" + decorationLength);
if (isStart) {
dotPath.moveStartPoint(new UTranslate(decorationLength, 0).rotate(angle - Math.PI));
} else {
dotPath.moveEndPoint(new UTranslate(decorationLength, 0).rotate(angle - Math.PI));
}
return extremityFactory.createUDrawable(center, angle, side);
}
private UDrawable getExtremity(final XPoint2D center, LinkDecor decor, PointListIterator pointListIterator,
double angle, Cluster cluster, SvekNode nodeContact) {
final ExtremityFactory extremityFactory = decor.getExtremityFactory(backgroundColor);
final ExtremityFactory extremityFactory = decor.getExtremityFactoryLegacy(backgroundColor);
if (cluster != null) {
if (extremityFactory != null) {
@ -515,8 +541,8 @@ public class SvekLine implements Moveable, Hideable, GuideLine {
final List<XPoint2D> points = pointListIterator.next();
if (points.size() == 0)
return null;
// throw new IllegalStateException();
// return extremityFactory.createUDrawable(center, angle, null);
// throw new IllegalStateException();
// return extremityFactory.createUDrawable(center, angle, null);
final XPoint2D p0 = points.get(0);
final XPoint2D p1 = points.get(1);
@ -583,32 +609,47 @@ public class SvekLine implements Moveable, Hideable, GuideLine {
ltail == null ? null : ltail.getRectangleArea());
final SvgResult lineSvg = fullSvg.substring(end);
PointListIterator pointListIterator = lineSvg.getPointsWithThisColor(lineColor);
PointListIterator pointListIterator = null;
final LinkType linkType = link.getType();
if (link.getLength() == 1 && isThereTwo(linkType) && count(pointListIterator.cloneMe()) == 2) {
// Sorry, this is ugly because of
// https://github.com/plantuml/plantuml/issues/1353
final List<XPoint2D> points = pointListIterator.next();
final XPoint2D p1 = points.get(1);
if (getLinkStrategy() == LinkStrategy.SIMPLIER) {
XPoint2D startPoint = dotPath.getStartPoint();
XPoint2D endPoint = dotPath.getEndPoint();
if (p1.distance(startPoint) < p1.distance(endPoint))
startPoint = p1;
else
endPoint = p1;
// dotPath.moveStartPoint(0, 5);
// dotPath.moveEndPoint(0, -15);
this.extremity1 = getExtremitySpecial(startPoint, linkType.getDecor2(), dotPath.getStartAngle() + Math.PI,
ltail, getSvekNode1());
this.extremity2 = getExtremitySpecial(endPoint, linkType.getDecor1(), dotPath.getEndAngle(), lhead,
getSvekNode2());
this.extremity1 = getExtremitySimplier(dotPath.getStartPoint(),
linkType.getDecor2().getExtremityFactoryComplete(backgroundColor),
dotPath.getStartAngle() + Math.PI, ltail, getSvekNode1(), true);
this.extremity2 = getExtremitySimplier(dotPath.getEndPoint(),
linkType.getDecor1().getExtremityFactoryComplete(backgroundColor), dotPath.getEndAngle(), lhead,
getSvekNode2(), false);
} else {
this.extremity1 = getExtremity(dotPath.getStartPoint(), linkType.getDecor2(), pointListIterator,
dotPath.getStartAngle() + Math.PI, ltail, getSvekNode1());
this.extremity2 = getExtremity(dotPath.getEndPoint(), linkType.getDecor1(), pointListIterator,
dotPath.getEndAngle(), lhead, getSvekNode2());
pointListIterator = lineSvg.getPointsWithThisColor(lineColor);
if (link.getLength() == 1 && isThereTwo(linkType) && count(pointListIterator.cloneMe()) == 2) {
// Sorry, this is ugly because of
// https://github.com/plantuml/plantuml/issues/1353
final List<XPoint2D> points = pointListIterator.next();
final XPoint2D p1 = points.get(1);
XPoint2D startPoint = dotPath.getStartPoint();
XPoint2D endPoint = dotPath.getEndPoint();
if (p1.distance(startPoint) < p1.distance(endPoint))
startPoint = p1;
else
endPoint = p1;
this.extremity1 = getExtremitySpecial(startPoint, linkType.getDecor2(),
dotPath.getStartAngle() + Math.PI, ltail, getSvekNode1());
this.extremity2 = getExtremitySpecial(endPoint, linkType.getDecor1(), dotPath.getEndAngle(), lhead,
getSvekNode2());
} else {
this.extremity1 = getExtremity(dotPath.getStartPoint(), linkType.getDecor2(), pointListIterator,
dotPath.getStartAngle() + Math.PI, ltail, getSvekNode1());
this.extremity2 = getExtremity(dotPath.getEndPoint(), linkType.getDecor1(), pointListIterator,
dotPath.getEndAngle(), lhead, getSvekNode2());
}
}
if (link.getEntity1().getLeafType() == LeafType.LOLLIPOP_HALF)
@ -617,7 +658,8 @@ public class SvekLine implements Moveable, Hideable, GuideLine {
if (link.getEntity2().getLeafType() == LeafType.LOLLIPOP_HALF)
getSvekNode2().addImpact(dotPath.getEndAngle());
if (extremity1 instanceof Extremity && extremity2 instanceof Extremity) {
if (getLinkStrategy() == LinkStrategy.LEGACY && extremity1 instanceof Extremity
&& extremity2 instanceof Extremity) {
final XPoint2D p1 = ((Extremity) extremity1).somePoint();
final XPoint2D p2 = ((Extremity) extremity2).somePoint();
if (p1 != null && p2 != null) {
@ -669,8 +711,8 @@ public class SvekLine implements Moveable, Hideable, GuideLine {
}
private boolean isThereTwo(final LinkType linkType) {
return linkType.getDecor2().getExtremityFactory(backgroundColor) != null
&& linkType.getDecor1().getExtremityFactory(backgroundColor) != null;
return linkType.getDecor2().getExtremityFactoryLegacy(backgroundColor) != null
&& linkType.getDecor1().getExtremityFactoryLegacy(backgroundColor) != null;
}
private int count(PointListIterator it) {

View File

@ -70,12 +70,16 @@ public abstract class Extremity implements UDrawable {
public abstract XPoint2D somePoint();
public XPoint2D isTooSmallSoGiveThePointCloserToThisOne(XPoint2D pt) {
return null;
}
// public XPoint2D isTooSmallSoGiveThePointCloserToThisOne(XPoint2D pt) {
// return null;
// }
public UTranslate getDeltaForKal() {
return UTranslate.none();
}
public double getDecorationLength() {
return 15;
}
}

View File

@ -85,6 +85,11 @@ public class ExtremityArrow extends Extremity {
return xContact;
}
@Override
public double getDecorationLength() {
return 6;
}
public void drawU(UGraphic ug) {
final HColor color = ug.getParam().getColor();
if (color == null)

View File

@ -60,6 +60,11 @@ class ExtremityCrowfoot extends Extremity {
this.side = side;
}
@Override
public double getDecorationLength() {
return 8;
}
public void drawU(UGraphic ug) {
final int xWing = 8;
final int yAperture = 8;

View File

@ -83,14 +83,14 @@ class ExtremityDiamond extends Extremity {
ug.draw(polygon);
}
@Override
public XPoint2D isTooSmallSoGiveThePointCloserToThisOne(XPoint2D pt) {
XPoint2D result = null;
for (XPoint2D p : polygon.getPoints())
if (result == null || p.distance(pt) < result.distance(pt))
result = p;
return result;
}
// @Override
// public XPoint2D isTooSmallSoGiveThePointCloserToThisOne(XPoint2D pt) {
// XPoint2D result = null;
// for (XPoint2D p : polygon.getPoints())
// if (result == null || p.distance(pt) < result.distance(pt))
// result = p;
//
// return result;
// }
}

View File

@ -47,6 +47,7 @@ class ExtremityTriangle extends Extremity {
private final boolean fill;
private final HColor backgroundColor;
private final XPoint2D contact;
private final int xWing;
@Override
public XPoint2D somePoint() {
@ -58,6 +59,7 @@ class ExtremityTriangle extends Extremity {
this.backgroundColor = backgroundColor;
this.fill = fill;
this.contact = new XPoint2D(p1.getX(), p1.getY());
this.xWing = xWing;
angle = manageround(angle);
polygon.addPoint(0, 0);
@ -69,12 +71,16 @@ class ExtremityTriangle extends Extremity {
}
public void drawU(UGraphic ug) {
if (backgroundColor != null) {
if (backgroundColor != null)
ug = ug.apply(backgroundColor.bg());
} else if (fill) {
else if (fill)
ug = ug.apply(HColors.changeBack(ug));
}
ug.draw(polygon);
}
@Override
public double getDecorationLength() {
return xWing;
}
}