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