2013-12-10 19:36:50 +00:00
|
|
|
/* ========================================================================
|
|
|
|
* PlantUML : a free UML diagram generator
|
|
|
|
* ========================================================================
|
|
|
|
*
|
2023-02-22 18:43:48 +00:00
|
|
|
* (C) Copyright 2009-2024, Arnaud Roques
|
2013-12-10 19:36:50 +00:00
|
|
|
*
|
2023-02-22 18:43:48 +00:00
|
|
|
* Project Info: https://plantuml.com
|
2013-12-10 19:36:50 +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:
|
|
|
|
*
|
2023-02-22 18:43:48 +00:00
|
|
|
* https://plantuml.com/patreon (only 1$ per month!)
|
|
|
|
* https://plantuml.com/paypal
|
2017-03-15 19:13:31 +00:00
|
|
|
*
|
2013-12-10 19:36:50 +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
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
package net.sourceforge.plantuml.svek;
|
|
|
|
|
|
|
|
import java.util.Collection;
|
|
|
|
|
2023-02-22 18:43:48 +00:00
|
|
|
import net.sourceforge.plantuml.abel.EntityPosition;
|
2023-02-26 18:51:17 +00:00
|
|
|
import net.sourceforge.plantuml.klimt.geom.Rankdir;
|
|
|
|
import net.sourceforge.plantuml.klimt.geom.RectangleArea;
|
2023-02-22 18:43:48 +00:00
|
|
|
import net.sourceforge.plantuml.klimt.geom.XPoint2D;
|
2013-12-10 19:36:50 +00:00
|
|
|
|
|
|
|
public class FrontierCalculator {
|
|
|
|
|
2016-04-04 19:05:10 +00:00
|
|
|
private static final double DELTA = 3 * EntityPosition.RADIUS;
|
2023-02-26 18:51:17 +00:00
|
|
|
private RectangleArea core;
|
|
|
|
private final RectangleArea initial;
|
2013-12-10 19:36:50 +00:00
|
|
|
|
2023-02-26 18:51:17 +00:00
|
|
|
public FrontierCalculator(RectangleArea initial, Collection<RectangleArea> insides, Collection<XPoint2D> points,
|
|
|
|
Rankdir rankdir) {
|
2013-12-10 19:36:50 +00:00
|
|
|
this.initial = initial;
|
2023-02-26 18:51:17 +00:00
|
|
|
for (RectangleArea in : insides)
|
2022-09-12 20:08:34 +00:00
|
|
|
if (core == null)
|
2013-12-10 19:36:50 +00:00
|
|
|
core = in;
|
2022-09-12 20:08:34 +00:00
|
|
|
else
|
2013-12-10 19:36:50 +00:00
|
|
|
core = core.merge(in);
|
2022-09-12 20:08:34 +00:00
|
|
|
|
2013-12-10 19:36:50 +00:00
|
|
|
if (core == null) {
|
2022-09-12 20:08:34 +00:00
|
|
|
final XPoint2D center = initial.getPointCenter();
|
2023-02-26 18:51:17 +00:00
|
|
|
core = new RectangleArea(center.getX() - 1, center.getY() - 1, center.getX() + 1, center.getY() + 1);
|
2013-12-10 19:36:50 +00:00
|
|
|
}
|
2022-09-12 20:08:34 +00:00
|
|
|
for (XPoint2D p : points)
|
2013-12-10 19:36:50 +00:00
|
|
|
core = core.merge(p);
|
2022-09-12 20:08:34 +00:00
|
|
|
|
2013-12-10 19:36:50 +00:00
|
|
|
boolean touchMinX = false;
|
|
|
|
boolean touchMaxX = false;
|
|
|
|
boolean touchMinY = false;
|
|
|
|
boolean touchMaxY = false;
|
2022-09-12 20:08:34 +00:00
|
|
|
for (XPoint2D p : points) {
|
|
|
|
if (p.getX() == core.getMinX())
|
2013-12-10 19:36:50 +00:00
|
|
|
touchMinX = true;
|
2022-09-12 20:08:34 +00:00
|
|
|
|
|
|
|
if (p.getX() == core.getMaxX())
|
2013-12-10 19:36:50 +00:00
|
|
|
touchMaxX = true;
|
2022-09-12 20:08:34 +00:00
|
|
|
|
|
|
|
if (p.getY() == core.getMinY())
|
2013-12-10 19:36:50 +00:00
|
|
|
touchMinY = true;
|
2022-09-12 20:08:34 +00:00
|
|
|
|
|
|
|
if (p.getY() == core.getMaxY())
|
2013-12-10 19:36:50 +00:00
|
|
|
touchMaxY = true;
|
2022-09-12 20:08:34 +00:00
|
|
|
|
2013-12-10 19:36:50 +00:00
|
|
|
}
|
2022-09-12 20:08:34 +00:00
|
|
|
if (touchMinX == false)
|
2013-12-10 19:36:50 +00:00
|
|
|
core = core.withMinX(initial.getMinX());
|
2022-09-12 20:08:34 +00:00
|
|
|
|
|
|
|
if (touchMaxX == false)
|
2013-12-10 19:36:50 +00:00
|
|
|
core = core.withMaxX(initial.getMaxX());
|
2022-09-12 20:08:34 +00:00
|
|
|
|
|
|
|
if (touchMinY == false)
|
2013-12-10 19:36:50 +00:00
|
|
|
core = core.withMinY(initial.getMinY());
|
2022-09-12 20:08:34 +00:00
|
|
|
|
|
|
|
if (touchMaxY == false)
|
2013-12-10 19:36:50 +00:00
|
|
|
core = core.withMaxY(initial.getMaxY());
|
2022-09-12 20:08:34 +00:00
|
|
|
|
2013-12-10 19:36:50 +00:00
|
|
|
boolean pushMinX = false;
|
|
|
|
boolean pushMaxX = false;
|
|
|
|
boolean pushMinY = false;
|
|
|
|
boolean pushMaxY = false;
|
2022-09-12 20:08:34 +00:00
|
|
|
for (XPoint2D p : points) {
|
2013-12-10 19:36:50 +00:00
|
|
|
if (p.getY() == core.getMinY() || p.getY() == core.getMaxY()) {
|
2022-09-12 20:08:34 +00:00
|
|
|
if (Math.abs(p.getX() - core.getMaxX()) < DELTA)
|
2013-12-10 19:36:50 +00:00
|
|
|
pushMaxX = true;
|
2022-09-12 20:08:34 +00:00
|
|
|
|
|
|
|
if (Math.abs(p.getX() - core.getMinX()) < DELTA)
|
2013-12-10 19:36:50 +00:00
|
|
|
pushMinX = true;
|
2022-09-12 20:08:34 +00:00
|
|
|
|
2013-12-10 19:36:50 +00:00
|
|
|
}
|
|
|
|
if (p.getX() == core.getMinX() || p.getX() == core.getMaxX()) {
|
2022-09-12 20:08:34 +00:00
|
|
|
if (Math.abs(p.getY() - core.getMaxY()) < DELTA)
|
2013-12-10 19:36:50 +00:00
|
|
|
pushMaxY = true;
|
2022-09-12 20:08:34 +00:00
|
|
|
|
|
|
|
if (Math.abs(p.getY() - core.getMinY()) < DELTA)
|
2013-12-10 19:36:50 +00:00
|
|
|
pushMinY = true;
|
2022-09-12 20:08:34 +00:00
|
|
|
|
2013-12-10 19:36:50 +00:00
|
|
|
}
|
|
|
|
}
|
2022-09-12 20:08:34 +00:00
|
|
|
for (XPoint2D p : points) {
|
2023-02-26 18:51:17 +00:00
|
|
|
if (rankdir == Rankdir.LEFT_TO_RIGHT) {
|
|
|
|
if (p.getX() == core.getMinX() && (p.getY() == core.getMinY() || p.getY() == core.getMaxY()))
|
|
|
|
pushMinX = false;
|
2022-09-12 20:08:34 +00:00
|
|
|
|
2023-02-26 18:51:17 +00:00
|
|
|
if (p.getX() == core.getMaxX() && (p.getY() == core.getMinY() || p.getY() == core.getMaxY()))
|
|
|
|
pushMaxX = false;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (p.getY() == core.getMinY() && (p.getX() == core.getMinX() || p.getX() == core.getMaxX()))
|
|
|
|
pushMinY = false;
|
|
|
|
|
|
|
|
if (p.getY() == core.getMaxY() && (p.getX() == core.getMinX() || p.getX() == core.getMaxX()))
|
|
|
|
pushMaxY = false;
|
|
|
|
}
|
2022-09-12 20:08:34 +00:00
|
|
|
|
2013-12-10 19:36:50 +00:00
|
|
|
}
|
2022-09-12 20:08:34 +00:00
|
|
|
if (pushMaxX)
|
2013-12-10 19:36:50 +00:00
|
|
|
core = core.addMaxX(DELTA);
|
2022-09-12 20:08:34 +00:00
|
|
|
|
|
|
|
if (pushMinX)
|
2013-12-10 19:36:50 +00:00
|
|
|
core = core.addMinX(-DELTA);
|
2022-09-12 20:08:34 +00:00
|
|
|
|
|
|
|
if (pushMaxY)
|
2013-12-10 19:36:50 +00:00
|
|
|
core = core.addMaxY(DELTA);
|
2022-09-12 20:08:34 +00:00
|
|
|
|
|
|
|
if (pushMinY)
|
2013-12-10 19:36:50 +00:00
|
|
|
core = core.addMinY(-DELTA);
|
2022-09-12 20:08:34 +00:00
|
|
|
|
2013-12-10 19:36:50 +00:00
|
|
|
}
|
|
|
|
|
2023-02-26 18:51:17 +00:00
|
|
|
public RectangleArea getSuggestedPosition() {
|
2013-12-10 19:36:50 +00:00
|
|
|
return core;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ensureMinWidth(double minWidth) {
|
|
|
|
final double delta = core.getMaxX() - core.getMinX() - minWidth;
|
|
|
|
if (delta < 0) {
|
|
|
|
double newMinX = core.getMinX() + delta / 2;
|
|
|
|
double newMaxX = core.getMaxX() - delta / 2;
|
|
|
|
final double error = newMinX - initial.getMinX();
|
|
|
|
if (error < 0) {
|
|
|
|
newMinX -= error;
|
|
|
|
newMaxX -= error;
|
|
|
|
}
|
|
|
|
core = core.withMinX(newMinX);
|
|
|
|
core = core.withMaxX(newMaxX);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|