001/* 002* ParameterVector -- A n-dimensional vector of Parameter objects. 003* 004* Copyright (C) 2009-2025, by Joseph A. Huwaldt. All rights reserved. 005* 006* This library is free software; you can redistribute it and/or 007* modify it under the terms of the GNU Lesser General Public 008* License as published by the Free Software Foundation; either 009* version 2 of the License, or (at your option) any later version. 010* 011* This library is distributed in the hope that it will be useful, 012* but WITHOUT ANY WARRANTY; without even the implied warranty of 013* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014* Lesser General Public License for more details. 015* 016* You should have received a copy of the GNU Lesser General Public License 017* along with this program; if not, write to the Free Software 018* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 019* Or visit: http://www.gnu.org/licenses/lgpl.html 020 */ 021package jahuwaldt.js.param; 022 023import java.util.List; 024import javax.measure.converter.ConversionException; 025import javax.measure.converter.UnitConverter; 026import javax.measure.quantity.Dimensionless; 027import javax.measure.quantity.Length; 028import javax.measure.quantity.Quantity; 029import javax.measure.unit.NonSI; 030import javax.measure.unit.SI; 031import javax.measure.unit.Unit; 032import javolution.context.ObjectFactory; 033import javolution.context.StackContext; 034import javolution.lang.MathLib; 035import javolution.lang.ValueType; 036import javolution.util.FastTable; 037import javolution.xml.XMLFormat; 038import javolution.xml.XMLSerializable; 039import javolution.xml.stream.XMLStreamException; 040import org.jscience.mathematics.number.Float64; 041import org.jscience.mathematics.vector.DimensionException; 042import org.jscience.mathematics.vector.Float64Vector; 043import org.jscience.mathematics.vector.Vector; 044 045/** 046 * <p> 047 * This class represents an n-dimensional {@link Vector vector} of {@link Parameter} 048 * elements sharing the same units.</p> 049 * 050 * <p> Modified by: Joseph A. Huwaldt </p> 051 * 052 * @author Joseph A. Huwaldt Date: March 27, 2009 053 * @version February 23, 2025 054 */ 055public class ParameterVector<Q extends Quantity> extends AbstractParamVector<Q, ParameterVector<Q>> 056 implements ValueType, XMLSerializable { 057 058 private static final long serialVersionUID = -1026285730707259617L; 059 060 /** 061 * Constant used to identify the X (0) coordinate in the vector. 062 */ 063 public static final int X = 0; 064 065 /** 066 * Constant used to identify the Y (1) coordinate in the vector. 067 */ 068 public static final int Y = 1; 069 070 /** 071 * Constant used to identify the Z (2) coordinate in the vector. 072 */ 073 public static final int Z = 2; 074 075 /** 076 * The coordinates are stored in this vector. Serialization is handled by this class 077 * since Float64Vector is not Serializable. 078 */ 079 protected transient Float64Vector _data; 080 081 /** 082 * Holds the unit of the coordinates. 083 */ 084 protected Unit<Q> _unit; 085 086 /** 087 * Returns a 2D {@link ParameterVector} instance holding the specified 088 * <code>double</code> values stated in the specified units. 089 * 090 * @param x the x value stated in the specified unit. 091 * @param y the y value stated in the specified unit. 092 * @param unit the unit in which the coordinates are stated. 093 * @param <Q> the quantity or type of the specified unit. 094 * @return the vector having the specified values. 095 */ 096 public static <Q extends Quantity> ParameterVector<Q> valueOf(double x, double y, Unit<Q> unit) { 097 ParameterVector<Q> V = newInstance(unit); 098 099 V._data = Float64Vector.valueOf(x, y); 100 101 return V; 102 } 103 104 /** 105 * Returns a {@link ParameterVector} instance holding the specified 106 * <code>double</code> values stated in the specified units. 107 * 108 * @param x the x value stated in the specified unit. 109 * @param y the y value stated in the specified unit. 110 * @param z the z value stated in the specified unit. 111 * @param unit the unit in which the coordinates are stated. 112 * @param <Q> the quantity or type of the specified unit. 113 * @return the vector having the specified values. 114 */ 115 public static <Q extends Quantity> ParameterVector<Q> valueOf(double x, double y, double z, Unit<Q> unit) { 116 ParameterVector<Q> V = newInstance(unit); 117 118 V._data = Float64Vector.valueOf(x, y, z); 119 120 return V; 121 } 122 123 /** 124 * Returns a {@link ParameterVector} instance holding the specified 125 * <code>double</code> values stated in the specified units. 126 * 127 * @param unit the unit in which the coordinates are stated. 128 * @param values A list of values to store in the vector. 129 * @param <Q> the quantity or type of the specified unit. 130 * @return the vector having the specified values. 131 */ 132 public static <Q extends Quantity> ParameterVector<Q> valueOf(Unit<Q> unit, double... values) { 133 ParameterVector<Q> V = newInstance(unit); 134 135 V._data = Float64Vector.valueOf(values); 136 137 return V; 138 } 139 140 /** 141 * Returns a {@link ParameterVector} instance holding the specified 142 * <code>Parameter</code> values. All the values are converted to the same units as 143 * the x value. 144 * 145 * @param x the x value. 146 * @param y the y value. 147 * @param z the z value. 148 * @param <Q> the quantity or type of the specified unit. 149 * @return the vector having the specified values in the units of x. 150 */ 151 public static <Q extends Quantity> ParameterVector<Q> valueOf(Parameter<Q> x, Parameter<Q> y, Parameter<Q> z) { 152 153 Unit<Q> unit = x.getUnit(); 154 ParameterVector<Q> V = newInstance(unit); 155 V._data = Float64Vector.valueOf(x.getValue(), y.getValue(unit), z.getValue(unit)); 156 157 return V; 158 } 159 160 /** 161 * Returns a {@link ParameterVector} instance holding the specified 162 * <code>Parameter</code> values. All the values are converted to the same units as 163 * the first value. 164 * 165 * @param values A list of values to store in the vector. 166 * @param <Q> the quantity or type of the specified unit. 167 * @return the vector having the specified values in the units of x. 168 */ 169 public static <Q extends Quantity> ParameterVector<Q> valueOf(List<Parameter<Q>> values) { 170 FastTable<Float64> valueList = FastTable.newInstance(); 171 172 Unit<Q> unit = values.get(0).getUnit(); 173 int size = values.size(); 174 for (int i = 0; i < size; ++i) { 175 Parameter<Q> param = values.get(i); 176 Float64 value = Float64.valueOf(param.getValue(unit)); 177 valueList.add(value); 178 } 179 180 ParameterVector<Q> V = newInstance(unit); 181 V._data = Float64Vector.valueOf(valueList); 182 183 FastTable.recycle(valueList); 184 185 return V; 186 } 187 188 /** 189 * Returns a {@link ParameterVector} instance holding the specified 190 * <code>Parameter</code> values. All the values are converted to the same units as 191 * the first value. 192 * 193 * @param values A list of values to store in the vector. 194 * @param <Q> the quantity or type of the specified unit. 195 * @return the vector having the specified values in the units of x. 196 */ 197 public static <Q extends Quantity> ParameterVector<Q> valueOf(Parameter<Q>... values) { 198 FastTable<Float64> valueList = FastTable.newInstance(); 199 200 Unit<Q> unit = values[0].getUnit(); 201 int size = values.length; 202 for (int i = 0; i < size; ++i) { 203 Parameter<Q> param = values[i]; 204 Float64 value = Float64.valueOf(param.getValue(unit)); 205 valueList.add(value); 206 } 207 208 ParameterVector<Q> V = newInstance(unit); 209 V._data = Float64Vector.valueOf(valueList); 210 211 FastTable.recycle(valueList); 212 213 return V; 214 } 215 216 /** 217 * Returns a {@link ParameterVector} instance containing the specified vector of 218 * Float64 values stated in the specified units. 219 * 220 * @param vector the vector of Float64 values stated in the specified unit. 221 * @param unit the unit in which the coordinates are stated. 222 * @param <Q> the quantity or type of the specified unit. 223 * @return the vector having the specified values. 224 */ 225 public static <Q extends Quantity> ParameterVector<Q> valueOf(Vector<Float64> vector, Unit<Q> unit) { 226 227 ParameterVector<Q> V = newInstance(unit); 228 V._data = Float64Vector.valueOf(vector); 229 230 return V; 231 } 232 233 /** 234 * Returns a {@link ParameterVector} instance containing the specified vector of 235 * Parameter values with compatible units. All the values are converted to the same 236 * units as the 1st value. 237 * 238 * @param vector the vector of Parameter values stated in the specified unit. 239 * @param <Q> the quantity or type of the specified unit. 240 * @return the vector having the specified values. 241 */ 242 public static <Q extends Quantity> ParameterVector<Q> valueOf(Vector<Parameter<Q>> vector) { 243 if (vector instanceof ParameterVector) 244 return (ParameterVector<Q>) vector; 245 246 Unit<Q> unit = vector.get(0).getUnit(); 247 FastTable<Float64> valueList = FastTable.newInstance(); 248 249 int size = vector.getDimension(); 250 for (int i = 0; i < size; ++i) { 251 Parameter<Q> param = vector.get(i); 252 Float64 value = Float64.valueOf(param.getValue(unit)); 253 valueList.add(value); 254 } 255 256 ParameterVector<Q> V = newInstance(unit); 257 V._data = Float64Vector.valueOf(valueList); 258 259 FastTable.recycle(valueList); 260 261 return V; 262 } 263 264 /** 265 * Returns a Vector3D representation of this vector if possible. 266 * 267 * @return A Vector3D that is equivalent to this vector 268 * @throws DimensionException if this vector has any number of dimensions other than 269 * 3. 270 */ 271 @Override 272 public Vector3D<Q> toVector3D() { 273 if (getDimension() != 3) 274 throw new DimensionException(RESOURCES.getString("pvNumElementsErr")); 275 return (Vector3D<Q>) Vector3D.valueOf(this); 276 } 277 278 /** 279 * Return the specified {@link Vector3D} object as a <code>ParameterVector</code> 280 * instance. 281 * 282 * @param vector The <code>Vector3D</code> object to be converted to a 283 * <code>ParameterVector</code>. 284 * @return A <code>ParameterVector</code> instance that is equivalent to the supplied 285 * <code>Vector3D</code> object. 286 */ 287 @Override 288 public ParameterVector<Q> fromVector3D(Vector3D<Q> vector) { 289 return (ParameterVector<Q>) ParameterVector.valueOf(vector); 290 } 291 292 /** 293 * Returns the number of elements held by this vector. 294 * 295 * @return this vector dimension. 296 */ 297 @Override 298 public int getDimension() { 299 return _data.getDimension(); 300 } 301 302 /** 303 * Returns the value of a Parameter from this vector. 304 * 305 * @param i the dimension index. 306 * @return the value of the parameter at <code>i</code>. 307 * @throws IndexOutOfBoundsException <code>(i < 0) || (i ≥ dimension())</code> 308 */ 309 @Override 310 public Parameter<Q> get(int i) { 311 return Parameter.valueOf(getValue(i), getUnit()); 312 } 313 314 /** 315 * Returns the value of the Parameter in this vector as a <code>double</code>, stated 316 * in this vector's {@link #getUnit unit}. 317 * 318 * @param i the dimension index. 319 * @return the value of the Parameter at <code>i</code>. 320 * @throws IndexOutOfBoundsException <code>(i < 0) || (i ≥ dimension())</code> 321 */ 322 @Override 323 public double getValue(int i) { 324 return _data.getValue(i); 325 } 326 327 /** 328 * Returns the {@link #norm}, magnitude, or length value of this vector. 329 * 330 * @return <code>this.norm().doubleValue()</code>. 331 */ 332 @Override 333 public double normValue() { 334 return _data.normValue(); 335 } 336 337 /** 338 * Returns the negation of this vector. 339 * 340 * @return <code>-this</code>. 341 */ 342 @Override 343 public ParameterVector<Q> opposite() { 344 ParameterVector<Q> V = newInstance(this._unit); 345 V._data = this._data.opposite(); 346 return V; 347 } 348 349 /** 350 * Returns the sum of this vector with the one specified. The unit of the output 351 * vector will be the units of this vector. 352 * 353 * @param that the vector to be added. 354 * @return <code>this + that</code>. 355 * @throws DimensionException if vector dimensions are different. 356 * @throws ConversionException if the input vector is not in units consistent with 357 * this vector. 358 */ 359 @Override 360 public ParameterVector<Q> plus(Vector<Parameter<Q>> that) { 361 362 if (that.getDimension() != this.getDimension()) 363 throw new DimensionException(); 364 365 // Convert input vector to a Float64Vector (with unit conversion if necessary). 366 Float64Vector thatData = toFloat64Vector(that, this._unit); 367 368 ParameterVector<Q> V = newInstance(this._unit); 369 V._data = this._data.plus(thatData); 370 371 return V; 372 } 373 374 /** 375 * Returns the sum of this vector with the parameter specified. The input parameter is 376 * added to each component of this vector. The unit of the output vector will be the 377 * units of this vector. 378 * 379 * @param that the parameter to be added to each element of this vector. 380 * @return <code>this + that</code>. 381 */ 382 @Override 383 public ParameterVector<Q> plus(Parameter<Q> that) { 384 385 // Convert input parameter to the units of this vector. 386 double thatValue = that.getValue(this._unit); 387 388 StackContext.enter(); 389 try { 390 FastTable<Float64> valueList = FastTable.newInstance(); 391 int numDims = _data.getDimension(); 392 for (int i = 0; i < numDims; ++i) { 393 double value = this._data.getValue(i) + thatValue; 394 valueList.add(Float64.valueOf(value)); 395 } 396 ParameterVector<Q> V = newInstance(this._unit); 397 V._data = Float64Vector.valueOf(valueList); 398 399 return StackContext.outerCopy(V); 400 } finally { 401 StackContext.exit(); 402 } 403 } 404 405 /** 406 * Returns the difference between this vector and the one specified. The unit of the 407 * output vector will be the units of this vector. 408 * 409 * @param that the vector to be subtracted. 410 * @return <code>this - that</code>. 411 * @throws DimensionException if vector dimensions are different. 412 * @throws ConversionException if the input vector is not in units consistent with 413 * this vector. 414 */ 415 @Override 416 public ParameterVector<Q> minus(Vector<Parameter<Q>> that) { 417 418 if (that.getDimension() != this.getDimension()) 419 throw new DimensionException(); 420 421 // Convert input vector to a Float64Vector (with unit conversion if necessary). 422 Float64Vector thatData = toFloat64Vector(that, this._unit); 423 424 ParameterVector<Q> V = newInstance(this._unit); 425 V._data = this._data.minus(thatData); 426 427 return V; 428 } 429 430 /** 431 * Subtracts the supplied Parameter from each element of this vector and returns the 432 * result. The unit of the output vector will be the units of this vector. 433 * 434 * @param that the Parameter to be subtracted from each element of this vector. 435 * @return <code>this - that</code>. 436 */ 437 @Override 438 public ParameterVector<Q> minus(Parameter<Q> that) { 439 440 // Convert input parameter to the units of this vector. 441 double thatValue = that.getValue(this._unit); 442 443 StackContext.enter(); 444 try { 445 FastTable<Float64> valueList = FastTable.newInstance(); 446 int numDims = _data.getDimension(); 447 for (int i = 0; i < numDims; ++i) { 448 double value = this._data.getValue(i) - thatValue; 449 valueList.add(Float64.valueOf(value)); 450 } 451 ParameterVector<Q> V = newInstance(this._unit); 452 V._data = Float64Vector.valueOf(valueList); 453 454 return StackContext.outerCopy(V); 455 } finally { 456 StackContext.exit(); 457 } 458 } 459 460 /** 461 * Returns the product of this vector with the specified coefficient. 462 * 463 * @param k the coefficient multiplier. 464 * @return <code>this times k</code> 465 */ 466 @Override 467 @SuppressWarnings({"unchecked", "rawtypes"}) 468 public ParameterVector times(Parameter k) { 469 ParameterVector V = FACTORY.object(); 470 471 V._unit = Parameter.productOf(this.getUnit(), k.getUnit()); 472 V._data = this._data.times(k.getValue()); 473 474 return V; 475 } 476 477 /** 478 * Returns the product of this vector with the specified coefficient. 479 * 480 * @param k the coefficient multiplier. 481 * @return <code>this times k</code> 482 */ 483 @Override 484 public ParameterVector<Q> times(double k) { 485 ParameterVector<Q> V = newInstance(this._unit); 486 V._data = _data.times(k); 487 return V; 488 } 489 490 /** 491 * Returns the dot product of this vector with the one specified. 492 * 493 * @param that the vector multiplier. 494 * @return <code>this times that</code> 495 * @throws DimensionException if <code>this.dimension() != that.dimension()</code> 496 * @see <a href="http://en.wikipedia.org/wiki/Dot_product"> 497 * Wikipedia: Dot Product</a> 498 */ 499 @SuppressWarnings("rawtypes") 500 @Override 501 public Parameter times(Vector that) { 502 503 if (that.getDimension() != this.getDimension()) 504 throw new DimensionException(); 505 506 // Convert input vector to a Float64Vector. 507 @SuppressWarnings("unchecked") 508 Float64Vector thatData = toFloat64Vector(that, null); 509 510 Float64 f = this._data.times(thatData); 511 Unit<?> unit = Parameter.productOf(this.getUnit(), ((Parameter) that.get(X)).getUnit()); 512 513 return Parameter.valueOf(f.doubleValue(), unit); 514 } 515 516 /** 517 * Returns the element-by-element product of this vector with the one specified. 518 * 519 * @param that the vector multiplier. 520 * @return <code>this .* that</code> 521 * @throws DimensionException if <code>this.dimension() != that.dimension()</code> 522 */ 523 @SuppressWarnings("rawtypes") 524 public ParameterVector timesEBE(Vector that) { 525 526 if (that.getDimension() != this.getDimension()) 527 throw new DimensionException(); 528 529 StackContext.enter(); 530 try { 531 // Convert input vector to a Float64Vector. 532 @SuppressWarnings("unchecked") 533 Float64Vector thatData = toFloat64Vector(that, null); 534 535 Unit<?> unit = Parameter.productOf(this.getUnit(), ((Parameter) that.get(X)).getUnit()); 536 537 // Carry out the multiplication. 538 FastTable<Float64> valueList = FastTable.newInstance(); 539 int size = getDimension(); 540 for (int i = 0; i < size; ++i) { 541 double value = this._data.getValue(i) * thatData.getValue(i); 542 valueList.add(Float64.valueOf(value)); 543 } 544 545 ParameterVector<?> V = newInstance(unit); 546 V._data = Float64Vector.valueOf(valueList); 547 548 return StackContext.outerCopy(V); 549 } finally { 550 StackContext.exit(); 551 } 552 } 553 554 /** 555 * Returns the cross product of two vectors. 556 * 557 * @param that the vector multiplier. 558 * @return <code>this x that</code> 559 * @throws DimensionException if 560 * <code>(that.getDimension() != this.getDimension())</code> 561 * @see <a href="http://en.wikipedia.org/wiki/Cross_product"> 562 * Wikipedia: Cross Product</a> 563 */ 564 @SuppressWarnings({"unchecked", "rawtypes"}) 565 @Override 566 public ParameterVector cross(Vector that) { 567 568 if (that.getDimension() != this.getDimension()) 569 throw new DimensionException(); 570 571 // Convert input vector to a Float64Vector. 572 Float64Vector thatData = toFloat64Vector(that, null); 573 574 Unit<?> unit = Parameter.productOf(this.getUnit(), ((Parameter) that.get(X)).getUnit()); 575 576 ParameterVector V = newInstance(unit); 577 V._data = this._data.cross(thatData); 578 579 return V; 580 } 581 582 /** 583 * Returns this vector with each element divided by the specified divisor. 584 * 585 * @param that the divisor. 586 * @return <code>this / that</code>. 587 */ 588 public ParameterVector<?> divide(Parameter<?> that) { 589 return times(that.inverse()); 590 } 591 592 /** 593 * Returns this vector converted to a unit vector by dividing all the vector's 594 * elements by the length ({@link #norm}) of this vector. 595 * 596 * @return This vector converted to a unit vector by dividing all the vector's 597 * elements by the length of this vector. 598 */ 599 @SuppressWarnings("unchecked") 600 public ParameterVector<Dimensionless> toUnitVector() { 601 double magnitude = this.normValue(); 602 if (this.getUnit().equals(Dimensionless.UNIT) && MathLib.abs(magnitude - 1) <= Parameter.EPS) 603 return (ParameterVector<Dimensionless>) this; 604 ParameterVector<Dimensionless> V = newInstance(Dimensionless.UNIT); 605 V._data = this._data.times(1.0 / magnitude); 606 return V; 607 } 608 609 /** 610 * Returns a copy of this vector {@link javolution.context.AllocatorContext allocated} 611 * by the calling thread (possibly on the stack). 612 * 613 * @return an identical and independent copy of this vector. 614 */ 615 @Override 616 public ParameterVector<Q> copy() { 617 return copyOf(this); 618 } 619 620 /** 621 * Returns the unit in which the {@link #getValue values} in this vector are stated 622 * in. 623 */ 624 @Override 625 public Unit<Q> getUnit() { 626 return _unit; 627 } 628 629 /** 630 * Returns the equivalent to this vector but stated in the specified unit. 631 * 632 * @param unit the unit of the vector to be returned. 633 * @return a vector equivalent to this vector but stated in the specified unit. 634 * @throws ConversionException if the current model does not allows for conversion to 635 * the specified unit. 636 */ 637 @SuppressWarnings("unchecked") 638 @Override 639 public <R extends Quantity> ParameterVector<R> to(Unit<R> unit) { 640 if ((_unit == unit) || this._unit.equals(unit)) 641 return (ParameterVector<R>) this; 642 643 StackContext.enter(); 644 try { 645 UnitConverter cvtr = Parameter.converterOf(_unit, unit); 646 if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary. 647 ParameterVector<R> result = (ParameterVector<R>) copyOf(this); 648 result._unit = unit; 649 return StackContext.outerCopy((ParameterVector<R>) result); 650 } 651 652 FastTable<Float64> valueList = FastTable.newInstance(); 653 int size = _data.getDimension(); 654 for (int i = 0; i < size; ++i) { 655 double value = cvtr.convert(_data.getValue(i)); 656 valueList.add(Float64.valueOf(value)); 657 } 658 659 ParameterVector<R> result = newInstance(unit); 660 result._data = Float64Vector.valueOf(valueList); 661 662 return StackContext.outerCopy(result); 663 } finally { 664 StackContext.exit(); 665 } 666 } 667 668 /** 669 * Casts this ParameterVector to a parameterized unit of specified nature or throw a 670 * <code>ClassCastException</code> if the dimension of the specified quantity and this 671 * parameter's unit dimension do not match. 672 * 673 * @param type the quantity class identifying the nature of the unit. 674 * @param <T> The quantity or type of the new unit 675 * @return this ParameterVector parameterized with the specified type. 676 * @throws ClassCastException if the dimension of this parameter's unit is different 677 * from the specified quantity dimension. 678 * @throws UnsupportedOperationException if the specified quantity class does not have 679 * a public static field named "UNIT" holding the standard unit for the quantity. 680 */ 681 @SuppressWarnings("unchecked") 682 public <T extends Quantity> ParameterVector<T> asType(Class<T> type) throws ClassCastException { 683 @SuppressWarnings("unused") 684 Unit<T> u = _unit.asType(type); // If no exception is thrown, the cast is valid. 685 return (ParameterVector<T>) this; 686 } 687 688 /** 689 * Returns the values stored in this vector, stated in this vector's 690 * {@link #getUnit unit}, as a Float64Vector. 691 * 692 * @return The values stored in this vector, stated in this vector's unit. 693 */ 694 public Float64Vector toFloat64Vector() { 695 return _data; 696 } 697 698 /** 699 * Compares this ParameterVector against the specified object for strict equality 700 * (same values and same units). 701 * 702 * @param obj the object to compare with. 703 * @return <code>true</code> if this vector is identical to that vector; 704 * <code>false</code> otherwise. 705 */ 706 @Override 707 public boolean equals(Object obj) { 708 if (this == obj) 709 return true; 710 if ((obj == null) || (obj.getClass() != this.getClass())) 711 return false; 712 713 ParameterVector<?> that = (ParameterVector<?>) obj; 714 if (!this._data.equals(that._data)) 715 return false; 716 717 return this._unit.equals(that._unit); 718 } 719 720 /** 721 * Returns the hash code for this parameter. 722 * 723 * @return the hash code value. 724 */ 725 @Override 726 public int hashCode() { 727 int hash = 7; 728 729 int var_code = _unit.hashCode(); 730 hash = hash * 31 + var_code; 731 732 var_code = _data.hashCode(); 733 hash = hash * 31 + var_code; 734 735 return hash; 736 } 737 738 /** 739 * Convert a vector of Parameter objects to a Float64Vector stated in the specified 740 * units. If the units are null, no conversion occurs. 741 */ 742 private static <Q extends Quantity> Float64Vector toFloat64Vector(Vector<Parameter<Q>> that, Unit<Q> unit) { 743 744 StackContext.enter(); 745 try { 746 Float64Vector thatData; 747 Unit<?> oldUnit; 748 if (that instanceof ParameterVector) { 749 ParameterVector<Q> V = ((ParameterVector<Q>) that); 750 thatData = V.toFloat64Vector(); 751 oldUnit = V.getUnit(); 752 753 } else if (that instanceof Coordinate3D) { 754 Vector3D<Q> T = ((Coordinate3D<Q>) that).toVector3D(); 755 if (!Length.UNIT.isCompatible(T.getUnit())) 756 throw new ConversionException(RESOURCES.getString("incompatibleUnits"). 757 replace("<NAME/>", "input vector").replace("<TYPE/>", "length")); 758 oldUnit = T.getUnit(); 759 thatData = T.toFloat64Vector(); 760 761 } else { 762 ParameterVector<Q> V = valueOf(that); 763 thatData = V.toFloat64Vector(); 764 oldUnit = V.getUnit(); 765 } 766 767 // Convert that vector's units to the specified units if necessary. 768 if (unit != null) { 769 if (!unit.equals(oldUnit)) { 770 UnitConverter cvtr = Parameter.converterOf(oldUnit, unit); 771 if (cvtr != UnitConverter.IDENTITY) { 772 FastTable<Float64> valueList = FastTable.newInstance(); 773 int size = thatData.getDimension(); 774 for (int i = 0; i < size; ++i) { 775 double value = cvtr.convert(thatData.getValue(i)); 776 valueList.add(Float64.valueOf(value)); 777 } 778 thatData = Float64Vector.valueOf(valueList); 779 } 780 } 781 } 782 783 return StackContext.outerCopy(thatData); 784 } finally { 785 StackContext.exit(); 786 } 787 } 788 789 /** 790 * During serialization, this will write out the Float64Vector as a simple series of 791 * <code>double</code> values. This method is ONLY called by the Java Serialization 792 * mechanism and should not otherwise be used. 793 * 794 * @param out The output stream to serialized this object to. 795 * @throws java.io.IOException if the output stream could not be written to. 796 */ 797 private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 798 799 // Call the default write object method. 800 out.defaultWriteObject(); 801 802 // Write out the number of elements. 803 int size = _data.getDimension(); 804 out.writeInt(size); 805 806 // Write out the coordinate values. 807 for (int i = 0; i < size; ++i) 808 out.writeDouble(_data.getValue(i)); 809 810 } 811 812 /** 813 * During de-serialization, this will handle the reconstruction of the Float64Vector. 814 * This method is ONLY called by the Java Serialization mechanism and should not 815 * otherwise be used. 816 * 817 * @param in The input stream to be de-serialized 818 * @throws java.io.IOException if there is a problem reading from the input stream. 819 * @throws ClassNotFoundException if the class could not be constructed. 820 */ 821 private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { 822 823 // Call the default read object method. 824 in.defaultReadObject(); 825 826 // Read in the number of elements. 827 int size = in.readInt(); 828 829 // Read in the coordinate values. 830 FastTable<Float64> valueList = FastTable.newInstance(); 831 for (int i = 0; i < size; ++i) { 832 double value = in.readDouble(); 833 valueList.add(Float64.valueOf(value)); 834 } 835 836 _data = Float64Vector.valueOf(valueList); 837 838 FastTable.recycle(valueList); 839 } 840 841 /** 842 * Holds the default XML representation. For example: 843 * <pre> 844 * <ParameterVector unit = "m"> 845 * <Float64 value="1.0" /> 846 * <Float64 value="0.0" /> 847 * <Float64 value="2.0" /> 848 * </ParameterVector> 849 * </pre> 850 */ 851 @SuppressWarnings("rawtypes") 852 protected static final XMLFormat<ParameterVector> XML = new XMLFormat<ParameterVector>(ParameterVector.class) { 853 854 @Override 855 public ParameterVector<?> newInstance(Class<ParameterVector> cls, InputElement xml) throws XMLStreamException { 856 857 Unit<?> unit = Unit.valueOf(xml.getAttribute("unit")); 858 ParameterVector<?> V = ParameterVector.newInstance(unit); 859 860 FastTable<Float64> valueList = FastTable.newInstance(); 861 while (xml.hasNext()) { 862 Float64 value = xml.getNext(); 863 valueList.add(value); 864 } 865 V._data = Float64Vector.valueOf(valueList); 866 867 FastTable.recycle(valueList); 868 869 return V; 870 } 871 872 @Override 873 public void read(InputElement xml, ParameterVector V) throws XMLStreamException { 874 // Nothing to do. 875 } 876 877 @Override 878 public void write(ParameterVector V, OutputElement xml) throws XMLStreamException { 879 880 xml.setAttribute("unit", V._unit.toString()); 881 int size = V._data.getDimension(); 882 for (int i = 0; i < size; ++i) 883 xml.add(V._data.get(i)); 884 885 } 886 }; 887 888 /////////////////////// 889 // Factory creation. // 890 /////////////////////// 891 protected ParameterVector() { 892 } 893 894 @SuppressWarnings("rawtypes") 895 private static final ObjectFactory<ParameterVector> FACTORY = new ObjectFactory<ParameterVector>() { 896 @Override 897 protected ParameterVector create() { 898 return new ParameterVector(); 899 } 900 }; 901 902 /** 903 * Return a new instance of the ParameterVector class with the specified unit. The 904 * <code>_data</code> value will be undefined and must be set before using the 905 * returned object for anything. 906 */ 907 @SuppressWarnings("unchecked") 908 protected static <Q extends Quantity> ParameterVector<Q> newInstance(Unit<Q> unit) { 909 if (unit == null) 910 throw new NullPointerException("Unit can not be null."); 911 ParameterVector<Q> measure = FACTORY.object(); 912 measure._unit = unit; 913 return measure; 914 } 915 916 @SuppressWarnings("unchecked") 917 private static <Q extends Quantity> ParameterVector<Q> copyOf(ParameterVector<Q> original) { 918 ParameterVector<Q> measure = FACTORY.object(); 919 measure._unit = original._unit; 920 measure._data = original._data.copy(); 921 return measure; 922 } 923 924 /** 925 * Tests the methods in this class. 926 * 927 * @param args the command-line arguments 928 */ 929 public static void main(String args[]) { 930 System.out.println("Testing ParameterVector: test = result [correct result]"); 931 932 ParameterVector<Length> v1 = ParameterVector.valueOf(1, 2, 3, NonSI.FOOT); 933 System.out.println("v1 = " + v1); 934 System.out.println(" converted to m = " + v1.to(SI.METER) + " [{0.3048 m, 0.6096 m, 0.9144 m}]"); 935 System.out.println(" v1.norm() = " + v1.norm() + " [3.74165738677394 ft]"); 936 System.out.println(" v1.opposite() = " + v1.opposite() + " [{-1.0 ft, -2.0 ft, -3.0 ft}]"); 937 System.out.println(" v1.toUnitVector() = " + v1.toUnitVector() + " [{0.267261241912424 , 0.534522483824849 , 0.801783725737273 }]"); 938 939 Parameter<Length> point = Parameter.valueOf(24, NonSI.INCH); 940 System.out.println("point = " + point); 941 System.out.println(" v1 + point = " + v1.plus(point) + " [{3.0 ft, 4.0 ft, 5.0 ft}]"); 942 System.out.println(" v1 - point = " + v1.minus(point) + " [{-1.0 ft, 0.0 ft, 1.0 ft}]"); 943 System.out.println(" v1 * 2 = " + v1.times(2) + " [{2.0 ft, 4.0 ft, 6.0 ft}]"); 944 945 ParameterVector<?> areaVector = (ParameterVector<?>) v1.times(point); 946 System.out.println(" v1 * point = " + areaVector); 947 System.out.println(" converted to ft² = " + areaVector.to(NonSI.SQUARE_FOOT) + " [{2.0 ft², 4.0 ft², 6.0 ft²}]"); 948 949 ParameterVector<Length> v2 = ParameterVector.valueOf(1, 1, 1, SI.METER); 950 ParameterVector<?> v1xv2 = (ParameterVector<?>) v1.cross(v2); 951 System.out.println("v2 = " + v2); 952 System.out.println(" v1 + v2 = " + v1.plus(v2) + " [{4.28083989501312 ft, 5.28083989501312 ft, 6.28083989501312 ft}]"); 953 System.out.println(" v1 - v2 = " + v1.minus(v2) + " [{-2.28083989501312 ft, -1.28083989501312 ft, -0.280839895013123 ft}]"); 954 System.out.println(" v1 · v2 = " + v1.times(v2.to(NonSI.FOOT)) + " [19.6850393700787 ft²]"); 955 System.out.println(" v1.cross(v2) = " + v1xv2.to(NonSI.FOOT.pow(2)) + " [{-3.28083989501312 ft^2, 6.56167979002625 ft^2, -3.28083989501312 ft^2}]"); 956 System.out.println(" v1.angle(v2) = " + v1.angle(v2).to(NonSI.DEGREE_ANGLE) + " [73.6090476746643 deg]"); 957 958 // Write out XML data. 959 try { 960 System.out.println(); 961 962 // Creates some useful aliases for class names. 963 javolution.xml.XMLBinding binding = new javolution.xml.XMLBinding(); 964 binding.setAlias(org.jscience.mathematics.number.Float64.class, "Float64"); 965 966 javolution.xml.XMLObjectWriter writer = javolution.xml.XMLObjectWriter.newInstance(System.out); 967 writer.setIndentation(" "); 968 writer.setBinding(binding); 969 writer.write(v1, "ParameterVector", ParameterVector.class); 970 writer.flush(); 971 972 System.out.println(); 973 } catch (Exception e) { 974 e.printStackTrace(); 975 } 976 } 977}