PageRenderTime 51ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Quark_Gems/src/org/openquark/gems/client/ConnectionRoute.java

http://github.com/levans/Open-Quark
Java | 389 lines | 160 code | 48 blank | 181 comment | 13 complexity | 171eba870ba9fe765e66115ca56c0640 MD5 | raw file
Possible License(s): BSD-3-Clause, BSD-2-Clause, IPL-1.0
  1. /*
  2. * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright notice,
  9. * this list of conditions and the following disclaimer.
  10. *
  11. * * Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * * Neither the name of Business Objects nor the names of its contributors
  16. * may be used to endorse or promote products derived from this software
  17. * without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  20. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  23. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  25. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  27. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  28. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  29. * POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. /*
  32. * ConnectionRoute.java
  33. * Creation date: (12/6/00 7:46:02 AM)
  34. * By: Luke Evans
  35. */
  36. package org.openquark.gems.client;
  37. import java.awt.Point;
  38. import java.util.ArrayList;
  39. import java.util.List;
  40. /**
  41. * A connection route describes a series of points to join to describe
  42. * a route from an initial point to a final point.
  43. * Creation date: (12/6/00 7:46:02 AM)
  44. * @author Luke Evans
  45. */
  46. public class ConnectionRoute {
  47. private final List<Point> points; // The path itself
  48. private int minX = 0, minY = 0, maxX = 0, maxY = 0;
  49. /**
  50. * Default ConnectionRoute constructor.
  51. */
  52. private ConnectionRoute() {
  53. super();
  54. points = new ArrayList<Point>(2);
  55. }
  56. /**
  57. * Construct a ConnectionRoute from start and end points.
  58. */
  59. public ConnectionRoute(Point start, Point end) {
  60. this();
  61. addPoint(start);
  62. addPoint(end);
  63. // Initialise the max and min (for bounds)
  64. minX = Math.min(start.x, end.x);
  65. maxX = Math.max(start.x, end.x);
  66. minY = Math.min(start.y, end.y);
  67. maxY = Math.max(start.y, end.y);
  68. }
  69. /**
  70. * Add a final leg based on a fraction extrapolation.
  71. * Creation date: (12/6/00 12:07:56 PM)
  72. */
  73. public void addFinalLeg(float extrapolation) {
  74. // Can only do this if we have more than 3 points
  75. int i = points.size();
  76. if (i < 3) {
  77. return;
  78. }
  79. // Get some points
  80. i--;
  81. Point lastPoint = points.get(i--);
  82. Point penultPoint = points.get(i--);
  83. Point antePenultPoint = points.get(i);
  84. // Work out an extrapolation of the penultimate line (scaled by the factor provided)
  85. Point delta = new Point(penultPoint.x - antePenultPoint.x, penultPoint.y - antePenultPoint.y);
  86. delta.x *= extrapolation;
  87. delta.y *= extrapolation;
  88. // Translate the penultPoint by this delta
  89. penultPoint.x += delta.x;
  90. penultPoint.y += delta.y;
  91. checkPoint(penultPoint);
  92. // Insert a new penultPoint
  93. points.add(points.size() - 1, checkPoint(new Point(lastPoint.x + delta.x, lastPoint.y + delta.y)));
  94. }
  95. /**
  96. * Add a final leg based on a fixed delta amount.
  97. * Creation date: (12/6/00 12:07:56 PM)
  98. */
  99. public void addFinalLeg(Point delta) {
  100. // Can only do this if we have more than 3 points
  101. int i = points.size();
  102. if (i < 3) {
  103. return;
  104. }
  105. // Get some points
  106. i--;
  107. Point lastPoint = points.get(i--);
  108. Point penultPoint = points.get(i--);
  109. // Translate the penultPoint by this delta
  110. penultPoint.x += delta.x;
  111. penultPoint.y += delta.y;
  112. checkPoint(penultPoint);
  113. // Insert a new penultPoint
  114. points.add(points.size() - 1, checkPoint(new Point(lastPoint.x + delta.x, lastPoint.y + delta.y)));
  115. }
  116. /**
  117. * Add the given point the end of the points list.
  118. * Creation date: (12/6/00 8:05:24 AM)
  119. * @param xy Point the point to add
  120. */
  121. public void addPoint(Point xy) {
  122. points.add(checkPoint(xy));
  123. }
  124. /**
  125. * Return the index of the point after the middle of the line.
  126. * Creation date: (12/6/00 8:58:00 AM)
  127. * @return int the index of the point
  128. */
  129. private int afterMiddle() {
  130. return (int) (points.size() / 2.0F + 0.5);
  131. }
  132. /**
  133. * Return the index of the point before the middle of the line.
  134. * Creation date: (12/6/00 8:58:00 AM)
  135. * @return int the index of the point
  136. */
  137. private int beforeMiddle() {
  138. return points.size()/2;
  139. }
  140. /**
  141. * Insert a new point after the 'middle' of the line.
  142. * Creation date: (12/6/00 8:07:18 AM)
  143. * @param xy Point the new point
  144. */
  145. public void bisectAfterMiddle(Point xy) {
  146. // Where is the insert point?
  147. int insert = afterMiddle();
  148. // Insert point
  149. points.add(insert, checkPoint(xy));
  150. }
  151. /**
  152. * Insert a new point after the 'middle' of the line.
  153. * Creation date: (12/6/00 8:07:18 AM)
  154. * @param xy Point the new point
  155. */
  156. public void bisectBeforeMiddle(Point xy) {
  157. // Where is the insert point?
  158. int insert = beforeMiddle();
  159. // Insert point
  160. points.add(insert, checkPoint(xy));
  161. }
  162. /**
  163. * Bisect with a horizontal line offset by delta from
  164. * the point before the centre. If delta is zero, we divide equally
  165. * Creation date: (12/6/00 8:55:12 AM)
  166. * @param delta int the offset to the horizontal line or 0 for equal split
  167. */
  168. public void bisectWithHorizontalLine(int delta) {
  169. // Get points around the middle
  170. int afterMiddle = beforeMiddle();
  171. int beforeMiddle = afterMiddle -1;
  172. Point beforePoint = points.get(beforeMiddle);
  173. Point afterPoint = points.get(afterMiddle);
  174. // Generate the new points
  175. Point firstPoint = new Point(beforePoint);
  176. Point secondPoint = new Point(afterPoint);
  177. // If delta is zero work out the split
  178. if (delta == 0) {
  179. delta = (secondPoint.y - firstPoint.y) / 2;
  180. }
  181. // To generate a horizontal line, we offset these points in the Y dimension
  182. firstPoint.y += delta;
  183. secondPoint.y = firstPoint.y;
  184. // Add these points
  185. bisectWithLine(firstPoint, secondPoint);
  186. }
  187. /**
  188. * Add the line xy1->xy2 to the middle of the connection.
  189. * Creation date: (12/6/00 8:33:30 AM)
  190. * @param xy1 Point the first point in the line
  191. * @param xy2 Point the second point in the line
  192. */
  193. public void bisectWithLine(Point xy1, Point xy2) {
  194. // Just insert the two points about the middle
  195. bisectBeforeMiddle(xy1);
  196. bisectAfterMiddle(xy2);
  197. }
  198. /**
  199. * Bisect with a vertical line offset by delta from
  200. * the point before the centre. If delta is zero, we divide equally
  201. * Creation date: (12/6/00 8:55:12 AM)
  202. * @param delta int the offset to the vertical line or 0 for equal split
  203. */
  204. public void bisectWithVerticalLine(int delta) {
  205. // Get points around the middle
  206. int afterMiddle = beforeMiddle();
  207. int beforeMiddle = afterMiddle -1;
  208. Point beforePoint = points.get(beforeMiddle);
  209. Point afterPoint = points.get(afterMiddle);
  210. // Generate the new points
  211. Point firstPoint = new Point(beforePoint);
  212. Point secondPoint = new Point(afterPoint);
  213. // If delta is zero work out the split
  214. if (delta == 0) {
  215. delta = (secondPoint.x - firstPoint.x) / 2;
  216. }
  217. // To generate a vertical line, we offset these points in the X dimension
  218. firstPoint.x += delta;
  219. secondPoint.x = firstPoint.x;
  220. // Add these points
  221. bisectWithLine(firstPoint, secondPoint);
  222. }
  223. /**
  224. * Check this point for relevance to the overall bounds of the route.
  225. * Creation date: (12/7/00 11:14:28 AM)
  226. * @return Point the point (so we can treat this as a filter)
  227. * @param point Point the point
  228. */
  229. private Point checkPoint(Point point) {
  230. maxX = Math.max(point.x, maxX);
  231. minX = Math.min(point.x, minX);
  232. maxY = Math.max(point.y, maxY);
  233. minY = Math.min(point.y, minY);
  234. return point;
  235. }
  236. /**
  237. * Draw this ConnectionRoute in the given graphics context.
  238. * Creation date: (12/6/00 9:14:10 AM)
  239. * @param g2d java.awt.Graphics2D
  240. */
  241. public void draw(java.awt.Graphics2D g2d) {
  242. // Just draw lines between each point
  243. int numPoints = points.size();
  244. for (int i = 1; i < numPoints; i++) {
  245. Point fromPoint = points.get(i - 1);
  246. Point toPoint = points.get(i);
  247. // workaround for a Mac bug in OS X:
  248. // negative delta's are not drawn properly in XOR mode, so we make all delta's positive
  249. int maxX = Math.max(toPoint.x, fromPoint.x);
  250. int minX = Math.min(toPoint.x, fromPoint.x);
  251. int maxY = Math.max(toPoint.y, fromPoint.y);
  252. int minY = Math.min(toPoint.y, fromPoint.y);
  253. // use the fact that connection routes are either horizontal or vertical
  254. // (this works only if minX and minY are from the same point)
  255. g2d.drawLine(minX, minY, maxX, maxY);
  256. // g2d.drawLine(fromPoint.x, fromPoint.y, toPoint.x, toPoint.y);
  257. }
  258. }
  259. /**
  260. * Return the first point in the route.
  261. * Creation date: (12/7/00 2:10:58 PM)
  262. * @return Point the point
  263. */
  264. private Point firstPoint() {
  265. return points.get(0);
  266. }
  267. /**
  268. * Generate a square path between source and destination suitable
  269. * for horizontal connectors
  270. * Creation date: (12/7/00 1:30:56 PM)
  271. * @return boolean true if suitable for extra leg
  272. */
  273. public boolean genSquareRouteForHorizontalConnectors() {
  274. // Get the first and last points
  275. Point first = firstPoint();
  276. Point last = lastPoint();
  277. // Determine whether to split vertically or horizontally
  278. if (last.x >= first.x) {
  279. bisectWithVerticalLine(0);
  280. return false;
  281. } else {
  282. bisectWithHorizontalLine(0);
  283. return true;
  284. }
  285. }
  286. /**
  287. * Generate a square path between source and destination suitable
  288. * for horizontal connectors. Add a final leg of the given size.
  289. * Creation date: (12/7/00 1:30:56 PM)
  290. */
  291. public void genSquareRouteForHorizontalConnectors(int extraFinalLegOffset) {
  292. if (genSquareRouteForHorizontalConnectors()) {
  293. addFinalLeg(new Point(extraFinalLegOffset, 0));
  294. }
  295. }
  296. /**
  297. * Generate a square path between source and destination suitable
  298. * for vertical connectors
  299. * Creation date: (12/7/00 1:30:56 PM)
  300. * @return boolean true if suitable for extra leg
  301. */
  302. public boolean genSquareRouteForVerticalConnectors() {
  303. // Get the first and last points
  304. Point first = firstPoint();
  305. Point last = lastPoint();
  306. // Determine whether to split vertically or horizontally
  307. if (last.y >= first.y) {
  308. bisectWithHorizontalLine(0);
  309. return false;
  310. } else {
  311. bisectWithVerticalLine(0);
  312. return true;
  313. }
  314. }
  315. /**
  316. * Generate a square path between source and destination suitable
  317. * for vertical connectors. Add a final leg of the given size.
  318. * Creation date: (12/7/00 1:30:56 PM)
  319. */
  320. public void genSquareRouteForVerticalConnectors(int extraFinalLegOffset) {
  321. if (genSquareRouteForVerticalConnectors()) {
  322. addFinalLeg(new Point(0, extraFinalLegOffset));
  323. }
  324. }
  325. /**
  326. * Insert the method's description here.
  327. * Creation date: (12/7/00 11:04:28 AM)
  328. * @return java.awt.Rectangle
  329. */
  330. public java.awt.Rectangle getBoundingRectangle() {
  331. return new java.awt.Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1);
  332. }
  333. /**
  334. * Return the last point in the route
  335. * Creation date: (12/7/00 2:12:09 PM)
  336. * @return Point the point
  337. */
  338. private Point lastPoint() {
  339. return points.get(points.size() - 1);
  340. }
  341. }