From 47f2995aa3962223af67120c9a6ecf3da94b4a90 Mon Sep 17 00:00:00 2001 From: Arnaud Roques Date: Fri, 24 Mar 2023 19:07:32 +0100 Subject: [PATCH] fix: fix several issues https://github.com/plantuml/plantuml/issues/1357 https://github.com/plantuml/plantuml/issues/1353 https://github.com/plantuml/plantuml/issues/1352 https://forum.plantuml.net/17654/malformed-layout-and-missing-arrows-on-large-amount-of-edges https://github.com/plantuml/plantuml/issues/1349 https://github.com/plantuml/plantuml/issues/1348 https://github.com/plantuml/plantuml/issues/1355 https://github.com/plantuml/plantuml/issues/166 --- src/net/sourceforge/plantuml/Option.java | 80 ++++++++++++++++++- src/net/sourceforge/plantuml/Run.java | 50 ++++++------ src/net/sourceforge/plantuml/abel/Link.java | 4 +- .../plantuml/sdot/SmetanaPath.java | 54 +++++++------ .../plantuml/statediagram/StateDiagram.java | 3 +- .../plantuml/svek/PointListIteratorImpl.java | 13 ++- .../sourceforge/plantuml/svek/SvekLine.java | 52 ++++++++++-- .../sourceforge/plantuml/svek/SvekNode.java | 18 +++-- .../plantuml/svek/image/EntityImageClass.java | 4 +- .../sourceforge/plantuml/version/Version.java | 6 +- 10 files changed, 209 insertions(+), 75 deletions(-) diff --git a/src/net/sourceforge/plantuml/Option.java b/src/net/sourceforge/plantuml/Option.java index 156ba223b..2f1db45a0 100644 --- a/src/net/sourceforge/plantuml/Option.java +++ b/src/net/sourceforge/plantuml/Option.java @@ -138,44 +138,64 @@ public class Option { System.setProperty("java.awt.headless", "true"); } else if (s.equalsIgnoreCase("-tsvg") || s.equalsIgnoreCase("-svg")) { setFileFormatOption(new FileFormatOption(FileFormat.SVG)); + } else if (s.equalsIgnoreCase("-tsvg:nornd") || s.equalsIgnoreCase("-svg:nornd")) { setFileFormatOption(new FileFormatOption(FileFormat.SVG)); + } else if (s.equalsIgnoreCase("-thtml") || s.equalsIgnoreCase("-html")) { setFileFormatOption(new FileFormatOption(FileFormat.HTML)); + } else if (s.equalsIgnoreCase("-tscxml") || s.equalsIgnoreCase("-scxml")) { setFileFormatOption(new FileFormatOption(FileFormat.SCXML)); + } else if (s.equalsIgnoreCase("-txmi") || s.equalsIgnoreCase("-xmi")) { setFileFormatOption(new FileFormatOption(FileFormat.XMI_STANDARD)); + } else if (s.equalsIgnoreCase("-txmi:argo") || s.equalsIgnoreCase("-xmi:argo")) { setFileFormatOption(new FileFormatOption(FileFormat.XMI_ARGO)); + } else if (s.equalsIgnoreCase("-txmi:star") || s.equalsIgnoreCase("-xmi:star")) { setFileFormatOption(new FileFormatOption(FileFormat.XMI_STAR)); + } else if (s.equalsIgnoreCase("-teps") || s.equalsIgnoreCase("-eps")) { setFileFormatOption(new FileFormatOption(FileFormat.EPS)); + } else if (s.equalsIgnoreCase("-teps:text") || s.equalsIgnoreCase("-eps:text")) { setFileFormatOption(new FileFormatOption(FileFormat.EPS_TEXT)); + } else if (s.equalsIgnoreCase("-ttxt") || s.equalsIgnoreCase("-txt")) { setFileFormatOption(new FileFormatOption(FileFormat.ATXT)); + } else if (s.equalsIgnoreCase("-tutxt") || s.equalsIgnoreCase("-utxt")) { setFileFormatOption(new FileFormatOption(FileFormat.UTXT)); + } else if (s.equalsIgnoreCase("-braille") || s.equalsIgnoreCase("-tbraille")) { setFileFormatOption(new FileFormatOption(FileFormat.BRAILLE_PNG)); + } else if (s.equalsIgnoreCase("-png") || s.equalsIgnoreCase("-tpng")) { setFileFormatOption(new FileFormatOption(FileFormat.PNG)); + } else if (s.equalsIgnoreCase("-vdx") || s.equalsIgnoreCase("-tvdx")) { setFileFormatOption(new FileFormatOption(FileFormat.VDX)); + } else if (s.equalsIgnoreCase("-latex") || s.equalsIgnoreCase("-tlatex")) { setFileFormatOption(new FileFormatOption(FileFormat.LATEX)); + } else if (s.equalsIgnoreCase("-latex:nopreamble") || s.equalsIgnoreCase("-tlatex:nopreamble")) { setFileFormatOption(new FileFormatOption(FileFormat.LATEX_NO_PREAMBLE)); + } else if (s.equalsIgnoreCase("-base64") || s.equalsIgnoreCase("-tbase64")) { setFileFormatOption(new FileFormatOption(FileFormat.BASE64)); + } else if (s.equalsIgnoreCase("-pdf") || s.equalsIgnoreCase("-tpdf")) { setFileFormatOption(new FileFormatOption(FileFormat.PDF)); + } else if (s.equalsIgnoreCase("-darkmode")) { setFileFormatOption(this.fileFormatOption.withColorMapper(ColorMapper.DARK_MODE)); + } else if (s.equalsIgnoreCase("-overwrite")) { OptionFlags.getInstance().setOverwrite(true); + } else if (s.equalsIgnoreCase("-output") || s.equalsIgnoreCase("-o")) { i++; if (i == arg.length) @@ -243,12 +263,16 @@ public class Option { } else if (s.equalsIgnoreCase("-failfast")) { this.failfast = true; + } else if (s.equalsIgnoreCase("-failfast2")) { this.failfast2 = true; + } else if (s.equalsIgnoreCase("-noerror")) { this.noerror = true; + } else if (s.equalsIgnoreCase("-checkonly")) { this.checkOnly = true; + } else if (s.equalsIgnoreCase("-theme")) { i++; if (i == arg.length) @@ -263,15 +287,20 @@ public class Option { initConfig(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg[i])); } else if (s.startsWith("-I")) { initInclude(s.substring(2)); + } else if (s.equalsIgnoreCase("-computeurl") || s.equalsIgnoreCase("-encodeurl")) { this.computeurl = true; + } else if (s.startsWith("-x")) { s = s.substring(2); excludes.add(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(s)); - } else if (s.equalsIgnoreCase("-verbose") || s.equalsIgnoreCase("-v")) { + + } else if (s.equalsIgnoreCase("-verbose") || s.equalsIgnoreCase("--verbose") || s.equalsIgnoreCase("-v")) { OptionFlags.getInstance().setVerbose(true); + } else if (s.equalsIgnoreCase("-pipe") || s.equalsIgnoreCase("-p")) { pipe = true; + } else if (s.equalsIgnoreCase("-pipedelimitor")) { i++; if (i == arg.length) @@ -280,19 +309,26 @@ public class Option { pipeDelimitor = arg[i]; } else if (s.equalsIgnoreCase("-pipemap")) { pipeMap = true; + } else if (s.equalsIgnoreCase("-pipenostderr")) { pipeNoStdErr = true; + } else if (s.equalsIgnoreCase("-syntax")) { syntax = true; OptionFlags.getInstance().setQuiet(true); + } else if (s.equalsIgnoreCase("-duration")) { duration = true; + } else if (s.equalsIgnoreCase("-debugsvek") || s.equalsIgnoreCase("-debug_svek")) { debugsvek = true; + } else if (s.equalsIgnoreCase("-keepfiles") || s.equalsIgnoreCase("-keepfile")) { System.err.println("-keepfiles option has been removed. Please consider -debugsvek instead"); + } else if (s.equalsIgnoreCase("-metadata")) { OptionFlags.getInstance().setExtractFromMetadata(true); + } else if (s.equalsIgnoreCase("-logdata")) { i++; if (i == arg.length) @@ -300,18 +336,24 @@ public class Option { OptionFlags.getInstance() .setLogData(new SFile(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg[i]))); + } else if (s.equalsIgnoreCase("-word")) { OptionFlags.getInstance().setWord(true); OptionFlags.getInstance().setQuiet(true); this.charset = "UTF-8"; + } else if (s.equalsIgnoreCase("-quiet")) { OptionFlags.getInstance().setQuiet(true); + } else if (s.equalsIgnoreCase("-decodeurl")) { this.decodeurl = true; - } else if (s.equalsIgnoreCase("-version")) { + + } else if (s.equalsIgnoreCase("-version") || s.equalsIgnoreCase("--version")) { OptionPrint.printVersion(); + } else if (s.matches("(?i)^-li[sc][ea]n[sc]e\\s*$")) { OptionPrint.printLicense(); + } else if (s.startsWith("-DPLANTUML_LIMIT_SIZE=")) { final String v = s.substring("-DPLANTUML_LIMIT_SIZE=".length()); if (v.matches("\\d+")) @@ -319,69 +361,101 @@ public class Option { } else if (s.startsWith("-D")) { manageDefine(s.substring(2)); + } else if (s.startsWith("-S")) { manageSkinParam(s.substring(2)); + } else if (s.startsWith("-P")) { managePragma(s.substring(2)); + } else if (s.equalsIgnoreCase("-testdot")) { OptionPrint.printTestDot(); + } else if (s.equalsIgnoreCase("-about") || s.equalsIgnoreCase("-author") || s.equalsIgnoreCase("-authors")) { OptionPrint.printAbout(); + } else if (s.equalsIgnoreCase("-help") || s.equalsIgnoreCase("-h") || s.equalsIgnoreCase("-?")) { OptionPrint.printHelp(); + } else if (s.equalsIgnoreCase("-language")) { OptionPrint.printLanguage(); + } else if (s.equalsIgnoreCase("-gui")) { OptionFlags.getInstance().setGui(true); + } else if (s.equalsIgnoreCase("-encodesprite")) { OptionFlags.getInstance().setEncodesprite(true); + } else if (s.equalsIgnoreCase("-printfonts")) { OptionFlags.getInstance().setPrintFonts(true); + } else if (s.equalsIgnoreCase("-dumphtmlstats")) { OptionFlags.getInstance().setDumpHtmlStats(true); + } else if (s.equalsIgnoreCase("-dumpstats")) { OptionFlags.getInstance().setDumpStats(true); + } else if (s.equalsIgnoreCase("-loopstats")) { OptionFlags.getInstance().setLoopStats(true); + } else if (s.equalsIgnoreCase("-enablestats")) { OptionFlags.getInstance().setEnableStats(true); + } else if (s.equalsIgnoreCase("-disablestats")) { OptionFlags.getInstance().setEnableStats(false); + } else if (s.equalsIgnoreCase("-extractstdlib")) { OptionFlags.getInstance().setExtractStdLib(true); + } else if (s.equalsIgnoreCase("-stdlib")) { OptionFlags.getInstance().setStdLib(true); + } else if (s.equalsIgnoreCase("-clipboard")) { OptionFlags.getInstance().setClipboard(true); + } else if (s.equalsIgnoreCase("-clipboardloop")) { OptionFlags.getInstance().setClipboardLoop(true); + } else if (s.equalsIgnoreCase("-htmlstats")) { StatsUtils.setHtmlStats(true); + } else if (s.equalsIgnoreCase("-xmlstats")) { StatsUtils.setXmlStats(true); + } else if (s.equalsIgnoreCase("-realtimestats")) { StatsUtils.setRealTimeStats(true); + } else if (s.equalsIgnoreCase("-useseparatorminus")) { OptionFlags.getInstance().setFileSeparator("-"); + } else if (s.equalsIgnoreCase("-splash")) { splash = true; + } else if (s.equalsIgnoreCase("-progress")) { textProgressBar = true; + } else if (s.equalsIgnoreCase("-nometadata")) { hideMetadata = true; + } else if (s.equalsIgnoreCase("-preproc")) { preprocessorOutput = OptionPreprocOutputMode.NORMAL; + } else if (s.equalsIgnoreCase("-cypher")) { preprocessorOutput = OptionPreprocOutputMode.CYPHER; + } else if (s.equalsIgnoreCase("-checkmetadata")) { checkMetadata = true; + } else if (s.equalsIgnoreCase("-stdrpt:1")) { stdrpt = 1; + } else if (s.equalsIgnoreCase("-stdrpt:2")) { stdrpt = 2; + } else if (s.equalsIgnoreCase("-stdrpt")) { stdrpt = 2; + } else if (s.equalsIgnoreCase("-pipeimageindex")) { i++; if (i == arg.length) @@ -402,10 +476,12 @@ public class Option { final String[] parts = s.split(":"); this.picowebPort = parts.length > 1 ? Integer.parseInt(parts[1]) : 8080; this.picowebBindAddress = parts.length > 2 ? parts[2] : null; + this.picowebEnableStop = StringUtils.goLowerCase(s).contains("stop"); } else if (s.startsWith("-c")) { s = s.substring(2); config.add(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(s)); + } else { result.add(s); } diff --git a/src/net/sourceforge/plantuml/Run.java b/src/net/sourceforge/plantuml/Run.java index 7686fe44c..91a88ebad 100644 --- a/src/net/sourceforge/plantuml/Run.java +++ b/src/net/sourceforge/plantuml/Run.java @@ -60,6 +60,7 @@ import net.sourceforge.plantuml.code.TranscoderUtil; import net.sourceforge.plantuml.file.FileGroup; import net.sourceforge.plantuml.file.SuggestedFile; import net.sourceforge.plantuml.ftp.FtpServer; +import net.sourceforge.plantuml.klimt.drawing.svg.SvgGraphics; import net.sourceforge.plantuml.klimt.sprite.SpriteGrayLevel; import net.sourceforge.plantuml.klimt.sprite.SpriteUtils; import net.sourceforge.plantuml.log.Logme; @@ -90,7 +91,7 @@ public class Run { if (argsArray.length > 0 && argsArray[0].equalsIgnoreCase("-headless")) System.setProperty("java.awt.headless", "true"); saveCommandLine(argsArray); - + final Option option = new Option(argsArray); ProgressBar.setEnable(option.isTextProgressBar()); if (OptionFlags.getInstance().isClipboardLoop()) { @@ -461,19 +462,8 @@ public class Run { throws IOException, InterruptedException { Log.info("Working on " + f.getPath()); if (OptionFlags.getInstance().isExtractFromMetadata()) { - System.out.println("------------------------"); - System.out.println(f); - // new Metadata().readAndDisplayMetadata(f); - System.out.println(); error.goOk(); - final String data = new MetadataTag(f, "plantuml").getData(); - // File file = SecurityUtils.File("tmp.txt"); - // PrintWriter pw = SecurityUtils.PrintWriter(file, "UTF-8"); - // pw.println(NastyEncoder.fromISO_8859_1(data)); - // pw.close(); - - System.out.println(data); - System.out.println("------------------------"); + extractMetadata(f); return; } final ISourceFileReader sourceFileReader; @@ -577,16 +567,28 @@ public class Run { error.goOk(); } -// public static void debugGantt() { -// final Locale locale = Locale.GERMAN; -// for (java.time.Month month : java.time.Month.values()) { -// System.err.println("Testing locale " + locale + " " + month); -// for (TextStyle style : TextStyle.values()) { -// final String s = month.getDisplayName(style, locale); -// System.err.println(style + " --> '" + s + "'"); -// -// } -// } -// } + private static void extractMetadata(File f) throws IOException { + System.out.println("------------------------"); + System.out.println(f); + System.out.println(); + if (f.getName().endsWith(".svg")) { + final SFile file = SFile.fromFile(f); + final String svg = FileUtils.readFile(file); + final int idx = svg.lastIndexOf(SvgGraphics.META_HEADER); + if (idx > 0) { + String part = svg.substring(idx + SvgGraphics.META_HEADER.length()); + final int idxEnd = part.indexOf("]"); + if (idxEnd > 0) { + part = part.substring(0, idxEnd); + final String decoded = TranscoderUtil.getDefaultTranscoderProtected().decode(part); + System.err.println(decoded); + } + } + } else { + final String data = new MetadataTag(f, "plantuml").getData(); + System.out.println(data); + } + System.out.println("------------------------"); + } } diff --git a/src/net/sourceforge/plantuml/abel/Link.java b/src/net/sourceforge/plantuml/abel/Link.java index 9bbb1479c..5f6ef4cf9 100644 --- a/src/net/sourceforge/plantuml/abel/Link.java +++ b/src/net/sourceforge/plantuml/abel/Link.java @@ -177,10 +177,10 @@ public class Link extends WithLinkType implements Hideable, Removeable { } public boolean isBetween(Entity cl1, Entity cl2) { - if (cl1.equals(this.cl1) && cl2.equals(this.cl2)) + if (cl1 == this.cl1 && cl2 == this.cl2) return true; - if (cl1.equals(this.cl2) && cl2.equals(this.cl1)) + if (cl1 == this.cl2 && cl2 == this.cl1) return true; return false; diff --git a/src/net/sourceforge/plantuml/sdot/SmetanaPath.java b/src/net/sourceforge/plantuml/sdot/SmetanaPath.java index ff9c15d40..5c9480860 100644 --- a/src/net/sourceforge/plantuml/sdot/SmetanaPath.java +++ b/src/net/sourceforge/plantuml/sdot/SmetanaPath.java @@ -49,6 +49,7 @@ import net.sourceforge.plantuml.klimt.UTranslate; import net.sourceforge.plantuml.klimt.color.ColorType; import net.sourceforge.plantuml.klimt.color.HColor; import net.sourceforge.plantuml.klimt.drawing.UGraphic; +import net.sourceforge.plantuml.klimt.geom.RectangleArea; import net.sourceforge.plantuml.klimt.geom.XPoint2D; import net.sourceforge.plantuml.klimt.shape.DotPath; import net.sourceforge.plantuml.klimt.shape.TextBlock; @@ -102,10 +103,25 @@ public class SmetanaPath implements UDrawable { color = this.link.getSpecificColor(); DotPath dotPath = getDotPathInternal(); - if (ymirror != null && dotPath != null) - dotPath = ymirror.getMirrored(dotPath); if (dotPath != null) { + if (ymirror != null) + dotPath = ymirror.getMirrored(dotPath); + + RectangleArea rectangleArea1 = null; + RectangleArea rectangleArea2 = null; + if (link.getEntity1().isGroup()) { + final Cluster cluster1 = bibliotekon.getCluster(link.getEntity1()); + rectangleArea1 = cluster1.getRectangleArea(); + + } + if (link.getEntity2().isGroup()) { + final Cluster cluster2 = bibliotekon.getCluster(link.getEntity2()); + rectangleArea2 = cluster2.getRectangleArea(); + } + + dotPath = dotPath.simulateCompound(rectangleArea2, rectangleArea1); + final LinkType linkType = link.getType(); UStroke stroke = linkType.getStroke3(diagram.getSkinParam().getThickness(LineParam.arrow, null)); if (link.getColors() != null && link.getColors().getSpecificLineStroke() != null) @@ -116,8 +132,8 @@ public class SmetanaPath implements UDrawable { ug.startUrl(url); ug.apply(stroke).apply(color).draw(dotPath); - printExtremityAtStart(ug.apply(color)); - printExtremityAtEnd(ug.apply(color)); + printExtremityAtStart(dotPath, ug.apply(color)); + printExtremityAtEnd(dotPath, ug.apply(color)); if (url != null) ug.closeUrl(); @@ -160,19 +176,15 @@ public class SmetanaPath implements UDrawable { return pt; } - private void printExtremityAtStart(UGraphic ug) { + private void printExtremityAtStart(DotPath dotPath, UGraphic ug) { final ExtremityFactory extremityFactory2 = link.getType().getDecor2() .getExtremityFactoryComplete(diagram.getSkinParam().getBackgroundColor()); if (extremityFactory2 == null) return; - final DotPath dotPath = getDotPathInternal(); - XPoint2D p0 = dotPath.getStartPoint(); - double startAngle = dotPath.getStartAngle(); - if (ymirror != null) { - p0 = ymirror.getMirrored(p0); - startAngle = -startAngle + Math.PI; - } + final XPoint2D p0 = dotPath.getStartPoint(); + final double startAngle = dotPath.getStartAngle() + Math.PI; + try { final UDrawable extremity2 = extremityFactory2.createUDrawable(p0, startAngle, null); if (extremity2 != null) @@ -184,19 +196,15 @@ public class SmetanaPath implements UDrawable { } } - private void printExtremityAtEnd(UGraphic ug) { + private void printExtremityAtEnd(DotPath dotPath, UGraphic ug) { final ExtremityFactory extremityFactory1 = link.getType().getDecor1() .getExtremityFactoryComplete(diagram.getSkinParam().getBackgroundColor()); if (extremityFactory1 == null) return; - final DotPath dotPath = getDotPathInternal(); - XPoint2D p0 = dotPath.getEndPoint(); - double endAngle = dotPath.getEndAngle(); - if (ymirror != null) { - p0 = ymirror.getMirrored(p0); - endAngle = -endAngle; - } + final XPoint2D p0 = dotPath.getEndPoint(); + final double endAngle = dotPath.getEndAngle(); + try { final UDrawable extremity1 = extremityFactory1.createUDrawable(p0, endAngle, null); if (extremity1 != null) @@ -282,12 +290,6 @@ public class SmetanaPath implements UDrawable { dotPath = dotPath.addCurve(ppt2, ppt3, ppt4); } - if (link.getEntity2().isGroup()) { - final Cluster cluster2 = bibliotekon.getCluster(link.getEntity2()); - // System.err.println("WARNING: a group " + cluster2.getRectangleArea()); - // dotPath = dotPath.simulateCompound(cluster2.getRectangleArea(), - // cluster2.getRectangleArea()); - } return dotPath; } diff --git a/src/net/sourceforge/plantuml/statediagram/StateDiagram.java b/src/net/sourceforge/plantuml/statediagram/StateDiagram.java index 62b38c72d..afde91c80 100644 --- a/src/net/sourceforge/plantuml/statediagram/StateDiagram.java +++ b/src/net/sourceforge/plantuml/statediagram/StateDiagram.java @@ -71,7 +71,8 @@ public class StateDiagram extends AbstractEntityDiagram { && getCurrentGroup() != existing.getParentContainer()) return false; - if (existing.getParentContainer().getGroupType() == GroupType.CONCURRENT_STATE + if (existing.getParentContainer() != null + && existing.getParentContainer().getGroupType() == GroupType.CONCURRENT_STATE && getCurrentGroup() != existing.getParentContainer()) return false; diff --git a/src/net/sourceforge/plantuml/svek/PointListIteratorImpl.java b/src/net/sourceforge/plantuml/svek/PointListIteratorImpl.java index a5b195211..95c97821d 100644 --- a/src/net/sourceforge/plantuml/svek/PointListIteratorImpl.java +++ b/src/net/sourceforge/plantuml/svek/PointListIteratorImpl.java @@ -49,9 +49,9 @@ class PointListIteratorImpl implements PointListIterator { static PointListIterator create(SvgResult svg, int lineColor) { final PointListIteratorImpl result = new PointListIteratorImpl(svg); final int idx = svg.getIndexFromColor(lineColor); - if (idx == -1) { + if (idx == -1) result.pos = -1; - } + return result; } @@ -66,16 +66,21 @@ class PointListIteratorImpl implements PointListIterator { } public boolean hasNext() { - return true; + return pos != -2; } public List next() { if (pos == -1) { + pos = -2; return Collections.emptyList(); } + try { final List result = svg.substring(pos).extractList(SvgResult.POINTS_EQUALS); - pos = svg.indexOf(SvgResult.POINTS_EQUALS, pos) + SvgResult.POINTS_EQUALS.length() + 1; + if (result.size() == 0) + pos = -2; + else + pos = svg.indexOf(SvgResult.POINTS_EQUALS, pos) + SvgResult.POINTS_EQUALS.length() + 1; return result; } catch (StringIndexOutOfBoundsException e) { Log.error("Error " + e); diff --git a/src/net/sourceforge/plantuml/svek/SvekLine.java b/src/net/sourceforge/plantuml/svek/SvekLine.java index 6b51c3bde..0897e536b 100644 --- a/src/net/sourceforge/plantuml/svek/SvekLine.java +++ b/src/net/sourceforge/plantuml/svek/SvekLine.java @@ -490,6 +490,12 @@ public class SvekLine implements Moveable, Hideable, GuideLine { return endUid.getPrefix(); } + private UDrawable getExtremitySpecial(final XPoint2D center, LinkDecor decor, double angle, Cluster cluster, + SvekNode nodeContact) { + final ExtremityFactory extremityFactory = decor.getExtremityFactory(backgroundColor); + return extremityFactory.createUDrawable(center, angle, null); + } + private UDrawable getExtremity(final XPoint2D center, LinkDecor decor, PointListIterator pointListIterator, double angle, Cluster cluster, SvekNode nodeContact) { final ExtremityFactory extremityFactory = decor.getExtremityFactory(backgroundColor); @@ -508,11 +514,13 @@ public class SvekLine implements Moveable, Hideable, GuideLine { if (extremityFactory != null) { final List points = pointListIterator.next(); if (points.size() == 0) - 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); final XPoint2D p2 = points.get(2); + Side side = null; if (nodeContact != null) side = nodeContact.getRectangleArea().getClosestSide(p1); @@ -577,10 +585,30 @@ public class SvekLine implements Moveable, Hideable, GuideLine { PointListIterator pointListIterator = lineSvg.getPointsWithThisColor(lineColor); final LinkType linkType = link.getType(); - 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.getLength() == 1 && isThereTwo(linkType) && count(pointListIterator.cloneMe()) == 2) { + // Sorry, this is ugly because of + // https://github.com/plantuml/plantuml/issues/1353 + + final List 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) getSvekNode1().addImpact(dotPath.getStartAngle() + Math.PI); @@ -639,6 +667,20 @@ public class SvekLine implements Moveable, Hideable, GuideLine { } + private boolean isThereTwo(final LinkType linkType) { + return linkType.getDecor2().getExtremityFactory(backgroundColor) != null + && linkType.getDecor1().getExtremityFactory(backgroundColor) != null; + } + + private int count(PointListIterator it) { + int nb = 0; + while (it.hasNext()) { + it.next(); + nb++; + } + return nb; + } + private SvekNode getSvekNode2() { return bibliotekon.getNode(link.getEntity2()); } diff --git a/src/net/sourceforge/plantuml/svek/SvekNode.java b/src/net/sourceforge/plantuml/svek/SvekNode.java index 183245c88..23ead13eb 100644 --- a/src/net/sourceforge/plantuml/svek/SvekNode.java +++ b/src/net/sourceforge/plantuml/svek/SvekNode.java @@ -276,22 +276,28 @@ public class SvekNode implements Positionable, Hideable { sb.append("label=<"); sb.append(""); - double position = 0; + int sum = 0; for (PortGeometry geom : ports.getAllPortGeometry()) { final String portId = geom.getId(); - final double missing = geom.getPosition() - position; + final int missing = (int) (geom.getPosition() - sum); + + sum += missing; appendTr(sb, null, missing); - appendTr(sb, portId, geom.getHeight()); - position = geom.getLastY(); + int intHeight = (int) geom.getHeight(); + + appendTr(sb, portId, intHeight); + sum += intHeight; } - appendTr(sb, null, getHeight() - position); + final double diff = getHeight() - sum; + appendTr(sb, null, (int) diff); + sb.append("
"); sb.append(">"); sb.append("];"); SvekUtils.println(sb); } - private void appendTr(StringBuilder sb, String portId, double height) { + private void appendTr(StringBuilder sb, String portId, int height) { if (height <= 0) return; diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageClass.java b/src/net/sourceforge/plantuml/svek/image/EntityImageClass.java index ff110e22a..9c9a23b78 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageClass.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageClass.java @@ -248,7 +248,7 @@ public class EntityImageClass extends AbstractEntityImage implements Stencil, Wi } public ShapeType getShapeType() { - if (((Entity) getEntity()).getPortShortNames().size() > 0) + if (getEntity().getPortShortNames().size() > 0) return ShapeType.RECTANGLE_HTML_FOR_PORTS; return ShapeType.RECTANGLE; @@ -256,7 +256,7 @@ public class EntityImageClass extends AbstractEntityImage implements Stencil, Wi @Override public Margins getShield(StringBounder stringBounder) { - return ((Entity) getEntity()).getMargins(); + return getEntity().getMargins(); } public double getStartingX(StringBounder stringBounder, double y) { diff --git a/src/net/sourceforge/plantuml/version/Version.java b/src/net/sourceforge/plantuml/version/Version.java index 3957d9577..10635e993 100644 --- a/src/net/sourceforge/plantuml/version/Version.java +++ b/src/net/sourceforge/plantuml/version/Version.java @@ -46,7 +46,7 @@ public class Version { private static final int MAJOR_SEPARATOR = 1000000; public static int version() { - return 1202304; + return 1202305; } public static int versionPatched() { @@ -82,7 +82,7 @@ public class Version { } public static int beta() { - final int beta = 6; + final int beta = 0; return beta; } @@ -95,7 +95,7 @@ public class Version { } public static long compileTime() { - return 1678388629831L; + return 1679680470757L; } public static String compileTimeString() {