summaryrefslogtreecommitdiff
path: root/src/net/sourceforge/plantuml/svek/ClusterPosition.java
blob: 6d3cb67d1a6916b5bc1760b688d38fcf865a5a26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/* ========================================================================
 * PlantUML : a free UML diagram generator
 * ========================================================================
 *
 * (C) Copyright 2009-2020, Arnaud Roques
 *
 * Project Info:  http://plantuml.com
 * 
 * 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
 * 
 * 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.awt.geom.CubicCurve2D;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;

import net.sourceforge.plantuml.Dimension2DDouble;
import net.sourceforge.plantuml.posimo.BezierUtils;

public class ClusterPosition {

	private final double minX;
	private final double minY;
	private final double maxX;
	private final double maxY;

	public ClusterPosition(double minX, double minY, double maxX, double maxY) {
		this.minX = minX;
		this.minY = minY;
		this.maxX = maxX;
		this.maxY = maxY;
	}

	public boolean contains(double x, double y) {
		return x >= minX && x < maxX && y >= minY && y < maxY;
	}

	public ClusterPosition merge(ClusterPosition other) {
		return new ClusterPosition(Math.min(this.minX, other.minX), Math.min(this.minY, other.minY), Math.max(
				this.maxX, other.maxX), Math.max(this.maxY, other.maxY));
	}

	public ClusterPosition merge(Point2D point) {
		final double x = point.getX();
		final double y = point.getY();
		return new ClusterPosition(Math.min(this.minX, x), Math.min(this.minY, y), Math.max(this.maxX, x), Math.max(
				this.maxY, y));
	}

	public boolean contains(Point2D p) {
		return contains(p.getX(), p.getY());
	}

	@Override
	public String toString() {
		return "minX=" + minX + " maxX=" + maxX + " minY=" + minY + " maxY=" + maxY;
	}

	public final double getMinX() {
		return minX;
	}

	public final double getMinY() {
		return minY;
	}

	public final double getMaxX() {
		return maxX;
	}

	public final double getMaxY() {
		return maxY;
	}

	public PointDirected getIntersection(CubicCurve2D.Double bez) {
		if (contains(bez.x1, bez.y1) == contains(bez.x2, bez.y2)) {
			return null;
		}
		final double dist = bez.getP1().distance(bez.getP2());
		if (dist < 2) {
			final double angle = BezierUtils.getStartingAngle(bez);
			return new PointDirected(bez.getP1(), angle);
		}
		final CubicCurve2D.Double left = new CubicCurve2D.Double();
		final CubicCurve2D.Double right = new CubicCurve2D.Double();
		bez.subdivide(left, right);
		final PointDirected int1 = getIntersection(left);
		if (int1 != null) {
			return int1;
		}
		final PointDirected int2 = getIntersection(right);
		if (int2 != null) {
			return int2;
		}
		throw new IllegalStateException();
	}

	public Point2D getPointCenter() {
		return new Point2D.Double((minX + maxX) / 2, (minY + maxY) / 2);
	}

	public ClusterPosition withMinX(double d) {
		return new ClusterPosition(d, minY, maxX, maxY);
	}

	public ClusterPosition withMaxX(double d) {
		return new ClusterPosition(minX, minY, d, maxY);
	}

	public ClusterPosition addMaxX(double d) {
		return new ClusterPosition(minX, minY, maxX + d, maxY);
	}

	public ClusterPosition addMaxY(double d) {
		return new ClusterPosition(minX, minY, maxX, maxY + d);
	}

	public ClusterPosition addMinX(double d) {
		return new ClusterPosition(minX + d, minY, maxX, maxY);
	}

	public ClusterPosition addMinY(double d) {
		return new ClusterPosition(minX, minY + d, maxX, maxY);
	}

	public ClusterPosition withMinY(double d) {
		return new ClusterPosition(minX, d, maxX, maxY);
	}

	public ClusterPosition withMaxY(double d) {
		return new ClusterPosition(minX, minY, maxX, d);
	}

	public Point2D getProjectionOnFrontier(Point2D pt) {
		final double x = pt.getX();
		final double y = pt.getY();
		if (x > maxX && y >= minY && y <= maxY) {
			return new Point2D.Double(maxX - 1, y);
		}
		if (x < minX && y >= minY && y <= maxY) {
			return new Point2D.Double(minX + 1, y);
		}
		if (y > maxY && x >= minX && x <= maxX) {
			return new Point2D.Double(x, maxY - 1);
		}
		if (y < minY && x >= minX && x <= maxX) {
			return new Point2D.Double(x, minY + 1);
		}
		return new Point2D.Double(x, y);
	}

	public ClusterPosition delta(double m1, double m2) {
		return new ClusterPosition(minX, minY, maxX + m1, maxY + m2);
	}

	public Dimension2D getDimension() {
		return new Dimension2DDouble(maxX - minX, maxY - minY);
	}

	public boolean isPointJustUpper(Point2D pt) {
		if (pt.getX() >= minX && pt.getX() <= maxX && pt.getY() <= minY) {
			return true;
		}
		return false;
	}

	public Side getClosestSide(Point2D pt) {
		final double distNorth = Math.abs(minY - pt.getY());
		final double distSouth = Math.abs(maxY - pt.getY());
		final double distWest = Math.abs(minX - pt.getX());
		final double distEast = Math.abs(maxX - pt.getX());
		if (isSmallerThan(distNorth, distWest, distEast, distSouth)) {
			return Side.NORTH;
		}
		if (isSmallerThan(distSouth, distNorth, distWest, distEast)) {
			return Side.SOUTH;
		}
		if (isSmallerThan(distEast, distNorth, distWest, distSouth)) {
			return Side.EAST;
		}
		if (isSmallerThan(distWest, distNorth, distEast, distSouth)) {
			return Side.WEST;
		}
		return null;
	}

	private boolean isSmallerThan(double value, double a, double b, double c) {
		return value <= a && value <= b && value <= c;
	}

}