001: /* ====================================================================
002: * The JRefactory License, Version 1.0
003: *
004: * Copyright (c) 2001 JRefactory. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by the
021: * JRefactory (http://www.sourceforge.org/projects/jrefactory)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. The names "JRefactory" must not be used to endorse or promote
026: * products derived from this software without prior written
027: * permission. For written permission, please contact seguin@acm.org.
028: *
029: * 5. Products derived from this software may not be called "JRefactory",
030: * nor may "JRefactory" appear in their name, without prior written
031: * permission of Chris Seguin.
032: *
033: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
034: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
035: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
036: * DISCLAIMED. IN NO EVENT SHALL THE CHRIS SEGUIN OR
037: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
038: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
039: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
040: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
041: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
042: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
043: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
044: * SUCH DAMAGE.
045: * ====================================================================
046: *
047: * This software consists of voluntary contributions made by many
048: * individuals on behalf of JRefactory. For more information on
049: * JRefactory, please see
050: * <http://www.sourceforge.org/projects/jrefactory>.
051: */
052: package org.acm.seguin.uml.line;
053:
054: import java.awt.Color;
055: import java.awt.Point;
056: import java.awt.Rectangle;
057: import java.awt.Graphics;
058:
059: /**
060: * Segment
061: *
062: *@author Chris Seguin
063: *@created July 28, 1999
064: */
065: class Segment {
066: /*<Instance Variables>*/
067: private double A0;
068: private double A1;
069: private double B0;
070: private double B1;
071: private double m;
072:
073: /*</Instance Variables>*/
074:
075: /*<Constructors>*/
076: /**
077: * Constructor for the Segment object
078: */
079: public Segment() {
080: A0 = 0;
081: A1 = 1;
082: B0 = 0;
083: B1 = 1;
084:
085: m = 1.414;
086: }
087:
088: /*</Setters>*/
089:
090: /*<Getters>*/
091: /**
092: * Gets the Point attribute of the Segment object
093: *
094: *@param t Description of Parameter
095: *@return The Point value
096: */
097: public Point getPoint(double t) {
098: return new Point((int) (A0 + t * A1), (int) (B0 + t * B1));
099: }
100:
101: /**
102: * Gets the ParamFromDistance attribute of the Segment object
103: *
104: *@param dist Description of Parameter
105: *@return The ParamFromDistance value
106: */
107: public double getParamFromDistance(double dist) {
108: if (dist > m) {
109: return (m - dist);
110: } else {
111: return dist / m;
112: }
113: }
114:
115: /*</Constructors>*/
116:
117: /*<Setters>*/
118: /**
119: * Description of the Method
120: *
121: *@param left Description of Parameter
122: *@param right Description of Parameter
123: */
124: public void reset(Rectangle left, Rectangle right) {
125: reset(left.getX() + left.getWidth() * 0.5, left.getY()
126: + left.getHeight() * 0.5, right.getX()
127: + right.getWidth() * 0.5, right.getY()
128: + right.getHeight() * 0.5);
129: }
130:
131: /**
132: * Description of the Method
133: *
134: *@param left Description of Parameter
135: *@param right Description of Parameter
136: */
137: public void reset(Point left, Point right) {
138: reset(left.getX(), left.getY(), right.getX(), right.getY());
139: }
140:
141: /**
142: * Description of the Method
143: *
144: *@param left Description of Parameter
145: *@param right Description of Parameter
146: */
147: public void reset(Rectangle left, Point right) {
148: reset(left.getX() + left.getWidth() * 0.5, left.getY()
149: + left.getHeight() * 0.5, right.getX(), right.getY());
150: }
151:
152: /**
153: * Description of the Method
154: *
155: *@param left Description of Parameter
156: *@param right Description of Parameter
157: */
158: public void reset(Point left, Rectangle right) {
159: reset(left.getX(), left.getY(), right.getX() + right.getWidth()
160: * 0.5, right.getY() + right.getHeight() * 0.5);
161: }
162:
163: private void reset(double X0, double Y0, double X1, double Y1) {
164: A0 = X0;
165: A1 = X1 - X0;
166:
167: B0 = Y0;
168: B1 = Y1 - Y0;
169:
170: m = Math.sqrt(A1 * A1 + B1 * B1);
171: }
172:
173: /**
174: * Intersects the rectangle with the segment
175: *
176: *@param rect The rectangle
177: *@return The parameter of the location on the line, -1 if it does not
178: * intersect
179: */
180: public double intersect(Rectangle rect) {
181: double left = rect.getX();
182: double right = rect.getX() + rect.getWidth();
183: double top = rect.getY();
184: double bottom = rect.getY() + rect.getHeight();
185:
186: double leftSide = -1;
187: double rightSide = -1;
188: if (Math.abs(A1) > 0.0001) {
189: leftSide = (left - A0) / A1;
190: rightSide = (right - A0) / A1;
191: }
192: double topSide = -1;
193: double bottomSide = -1;
194: if (Math.abs(B1) > 0.001) {
195: topSide = (top - B0) / B1;
196: bottomSide = (bottom - B0) / B1;
197: }
198:
199: if (inRectangle(leftSide, rect)) {
200: return leftSide;
201: } else if (inRectangle(rightSide, rect)) {
202: return rightSide;
203: } else if (inRectangle(topSide, rect)) {
204: return topSide;
205: } else if (inRectangle(bottomSide, rect)) {
206: return bottomSide;
207: }
208:
209: return -1;
210: }
211:
212: /**
213: * Determines the distance between a point and a segment
214: *
215: *@param point The point
216: *@return Returns the distance between the segment and the point or
217: * -1 if the point is closer to an end
218: */
219: public double distanceToPoint(Point point) {
220: double vX1 = A1;
221: double vY1 = B1;
222: double vX2 = point.getX() - A0;
223: double vY2 = point.getY() - B0;
224:
225: double magV2Square = vX2 * vX2 + vY2 * vY2;
226: double magV1Square = vX1 * vX1 + vY1 * vY1;
227:
228: double dotProduct = vX1 * vX2 + vY1 * vY2;
229:
230: if ((dotProduct < 0) || (dotProduct > magV1Square)) {
231: return -1.0;
232: }
233:
234: double dist = Math.sqrt(magV2Square - dotProduct * dotProduct
235: / magV1Square);
236:
237: return dist;
238: }
239:
240: /**
241: * Returns a parameter on the line that is a given distance from the end of
242: * the segment
243: *
244: *@param desiredDistance the desired distance
245: *@return the parameter
246: */
247: public double findFromEnd(double desiredDistance) {
248: double p = Math.sqrt(A1 * A1 + B1 * B1);
249: return 1 - desiredDistance / p;
250: }
251:
252: /**
253: * Returns a point above the line
254: *
255: *@param t Description of Parameter
256: *@param dist Description of Parameter
257: *@return Description of the Returned Value
258: */
259: public Point aboveLine(double t, double dist) {
260: if (Math.abs(A1) < 0.001) {
261: Point temp = getPoint(t);
262: return new Point((int) (temp.getX() - dist), (int) temp
263: .getY());
264: }
265:
266: Point p4 = getPoint(t);
267: double x4 = p4.getX();
268: double y4 = p4.getY();
269:
270: double a = B1 * B1 + A1 * A1;
271: double b = -2 * y4 * a;
272: double c = y4 * y4 * a - A1 * A1 * dist * dist;
273:
274: double y5 = (-b + Math.sqrt(b * b - 4 * a * c)) / (2 * a);
275: double x5 = -B1 * (y5 - y4) / A1 + x4;
276:
277: return new Point((int) x5, (int) y5);
278: }
279:
280: /**
281: * Returns a point below the line
282: *
283: *@param t Description of Parameter
284: *@param dist Description of Parameter
285: *@return Description of the Returned Value
286: */
287: public Point belowLine(double t, double dist) {
288: if (Math.abs(A1) < 0.001) {
289: Point temp = getPoint(t);
290: return new Point((int) (temp.getX() + dist), (int) temp
291: .getY());
292: }
293:
294: Point p4 = getPoint(t);
295: double x4 = p4.getX();
296: double y4 = p4.getY();
297:
298: double a = B1 * B1 + A1 * A1;
299: double b = -2 * y4 * a;
300: double c = y4 * y4 * a - A1 * A1 * dist * dist;
301:
302: double y5 = (-b - Math.sqrt(b * b - 4 * a * c)) / (2 * a);
303: double x5 = -B1 * (y5 - y4) / A1 + x4;
304:
305: return new Point((int) x5, (int) y5);
306: }
307:
308: /**
309: * Determines whether a particular point on the line is on the rectangle
310: *
311: *@param t the parameter that specifies the point
312: *@param rect the rectangle
313: *@return true if the point is in the rectangle
314: */
315: private boolean inRectangle(double t, Rectangle rect) {
316: if ((t < 0) || (t > 1)) {
317: return false;
318: }
319:
320: double X0 = A0 + A1 * t;
321: double Y0 = B0 + B1 * t;
322:
323: double left = rect.getX();
324: double right = rect.getX() + rect.getWidth();
325: double top = rect.getY();
326: double bottom = rect.getY() + rect.getHeight();
327:
328: return (left <= X0) && (right >= X0) && (top <= Y0)
329: && (bottom >= Y0);
330: }
331: /*</Getters>*/
332: }
|