View Javadoc

1   /*
2    * jcurl java curling software framework http://www.jcurl.org Copyright (C)
3    * 2005-2009 M. Rohrmoser
4    * 
5    * This program is free software; you can redistribute it and/or modify it under
6    * the terms of the GNU General Public License as published by the Free Software
7    * Foundation; either version 2 of the License, or (at your option) any later
8    * version.
9    * 
10   * This program is distributed in the hope that it will be useful, but WITHOUT
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13   * details.
14   * 
15   * You should have received a copy of the GNU General Public License along with
16   * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17   * Place, Suite 330, Boston, MA 02111-1307 USA
18   */
19  package org.jcurl.math;
20  
21  import java.awt.geom.AffineTransform;
22  import java.awt.geom.Point2D;
23  
24  /**
25   * Helper class that brings some (2D-)vector artihmetics.
26   * 
27   * @author <a href="mailto:m@jcurl.org">M. Rohrmoser </a>
28   * @version $Id:MathVec.java 682 2007-08-12 21:25:04Z mrohrmoser $
29   */
30  public final class MathVec {
31  	public static final double abs2D(final Point2D a) {
32  		return a.distance(0, 0);
33  	}
34  
35  	public static final Point2D add(final Point2D a, final Point2D b,
36  			final Point2D c) {
37  		final Point2D ret = ensureInstance(a, c);
38  		ret.setLocation(a.getX() + b.getX(), a.getY() + b.getY());
39  		return ret;
40  	}
41  
42  	/**
43  	 * Ensure c isn't <code>null</code>, if so create a new instance of the
44  	 * type of <code>template</code>.
45  	 * 
46  	 * @param template
47  	 * @param c
48  	 * @return <code>c</code> or
49  	 *         <code>template.getClass().newInstance()</code>
50  	 */
51  	public static final Point2D ensureInstance(final Point2D template,
52  			final Point2D c) {
53  		if (c != null)
54  			return c;
55  		// try {
56  		// return (Point2D) template.getClass().newInstance();
57  		return (Point2D) template.clone();
58  		// } catch (InstantiationException e) {
59  		// throw new RuntimeException("Couldn't create a new instance.", e);
60  		// } catch (IllegalAccessException e) {
61  		// throw new RuntimeException("Couldn't create a new instance.", e);
62  		// }
63  	}
64  
65  	/**
66  	 * Solve a linear equation of the form a*x=b.
67  	 * <p>
68  	 * See Numerische Mathematik, H. R. Schwarz, B. G. Teubner Verlag, 1998,
69  	 * S.22f.
70  	 * </p>
71  	 * 
72  	 * @param a
73  	 *            coefficient matrix. Attention! All fields a[i][j] are
74  	 *            overwritten!
75  	 * @param b
76  	 *            constant vector. Attention! All fields b[i] are overwritten!
77  	 * @param x
78  	 *            solution (max be null)
79  	 * @return x solution of a*x=b
80  	 */
81  	public static final double[] gauss(final double[][] a, final double[] b,
82  			double[] x) {
83  		final int n = a.length;
84  		// check parameters
85  		if (n != a[0].length)
86  			throw new IllegalArgumentException(
87  					"Matrix a must be quadratic but is " + n + "x"
88  							+ a[0].length);
89  		if (n != b.length)
90  			throw new IllegalArgumentException(
91  					"Dimension of vector b must match Matrix a but is "
92  							+ b.length);
93  		if (x == null)
94  			x = new double[n];
95  		if (n != x.length)
96  			throw new IllegalArgumentException(
97  					"Dimension of vector x must match Matrix a but is "
98  							+ x.length);
99  		// start to work
100 		double det = 1;
101 		final int p[] = new int[n];
102 		outer: for (int k = 0; k < n - 1; k++) {
103 			double max = 0;
104 			p[k] = 0;
105 			for (int i = k; i < n; i++) {
106 				double s = 0;
107 				for (int j = k; j < n; j++)
108 					s += Math.abs(a[i][j]);
109 				final double q = Math.abs(a[i][k]) / s;
110 				if (q > max) {
111 					max = q;
112 					p[k] = i;
113 				}
114 			}
115 			if (max == 0)
116 				break outer;
117 			if (p[k] != k) {
118 				det = -det;
119 				for (int j = 0; j < n; j++) {
120 					final double h = a[k][j];
121 					a[k][j] = a[p[k]][j];
122 					a[p[k]][j] = h;
123 				}
124 			}
125 			det *= a[k][k];
126 			for (int i = k + 1; i < n; i++) {
127 				a[i][k] /= a[k][k];
128 				for (int j = k + 1; j < n; j++)
129 					a[i][j] -= a[i][k] * a[k][j];
130 			}
131 		}
132 		det *= a[n - 1][n - 1];
133 		// Vorwärtseinsetzen
134 		for (int k = 0; k < n - 1; k++)
135 			if (p[k] != k) {
136 				final double h = b[k];
137 				b[k] = b[p[k]];
138 				b[p[k]] = h;
139 			}
140 		final double[] c = new double[n];
141 		for (int i = 0; i < n; i++) {
142 			c[i] = b[i];
143 			for (int j = 0; j < i - 1; j++)
144 				c[i] -= a[i][j] * c[j];
145 		}
146 		// Rückwärtseinsetzen
147 		for (int i = n - 1; i >= 0; i--) {
148 			double s = c[i];
149 			for (int k = i + 1; k < n; k++)
150 				s += a[i][k] * x[k];
151 			x[i] = -s / a[i][i];
152 		}
153 		return x;
154 	}
155 
156 	/**
157 	 * Helper to check (inclusive) interval containment. Robust against
158 	 * {@link Double#NaN} etc.
159 	 * 
160 	 * @param x
161 	 * @param a
162 	 * @param b
163 	 * @param allowSwap
164 	 *            may <code>a &gt; b</code>?
165 	 * @return is <code>x</code> within <code>a</code> and <code>b</code>?
166 	 */
167 	static final boolean isInside(final double x, double a, double b,
168 			final boolean allowSwap) {
169 		if (Double.isNaN(x) || Double.isInfinite(x))
170 			return false;
171 		if (Double.isNaN(a) || Double.isNaN(b))
172 			return true;
173 		if (allowSwap && a > b) {
174 			final double t = a;
175 			a = b;
176 			b = t;
177 		}
178 		return a <= x && x <= b;
179 	}
180 
181 	public static final double[] mult(final double fact, final double[] a,
182 			double[] b) {
183 		if (b == null)
184 			b = new double[a.length];
185 		for (int i = a.length - 1; i >= 0; i--)
186 			b[i] = a[i] * fact;
187 		return b;
188 	}
189 
190 	public static final Point2D mult(final double fact, final Point2D a,
191 			Point2D b) {
192 		b = ensureInstance(a, b);
193 		b.setLocation(a.getX() * fact, a.getY() * fact);
194 		return b;
195 	}
196 
197 	public static final Point2D norm(final Point2D a, final Point2D dst) {
198 		return mult(1.0 / abs2D(a), a, dst);
199 	}
200 
201 	/**
202 	 * TUNE JDK 1.6 brings an optimized {@link AffineTransform#rotate(double)}
203 	 */
204 	public static final void rotate(final AffineTransform t, final double vx,
205 			final double vy) {
206 		t.rotate(Math.atan2(vy, vx));
207 	}
208 
209 	public static final double scal(final double[] a, final double[] b) {
210 		if (a.length != b.length)
211 			throw new IllegalArgumentException();
212 		double ret = 0;
213 		for (int i = a.length - 1; i >= 0; i--)
214 			ret += a[i] * b[i];
215 		return ret;
216 	}
217 
218 	public static final double scal(final Point2D a, final Point2D b) {
219 		return a.getX() * b.getX() + a.getY() * b.getY();
220 	}
221 
222 	public static final double sqr(final double a) {
223 		return a * a;
224 	}
225 
226 	public static final Point2D sub(final Point2D a, final Point2D b,
227 			final Point2D dst) {
228 		final Point2D ret = ensureInstance(a, dst);
229 		ret.setLocation(a.getX() - b.getX(), a.getY() - b.getY());
230 		return ret;
231 	}
232 
233 	private MathVec() {}
234 }