001/** 002 * MutableVector -- Holds the floating point coordinates of an nD vector that can be 003 * changed. 004 * 005 * Copyright (C) 2009-2015, Joseph A. Huwaldt. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or modify it under the terms 008 * of the GNU Lesser General Public License as published by the Free Software Foundation; 009 * either version 2.1 of the License, or (at your option) any later version. 010 * 011 * This library is distributed in the hope that it will be useful, but WITHOUT ANY 012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 013 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public License along with 016 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - 017 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html 018 */ 019package geomss.geom; 020 021import jahuwaldt.js.param.*; 022import java.text.MessageFormat; 023import java.util.List; 024import java.util.Objects; 025import static java.util.Objects.requireNonNull; 026import javax.measure.converter.ConversionException; 027import javax.measure.converter.UnitConverter; 028import javax.measure.quantity.*; 029import javax.measure.unit.Unit; 030import javolution.context.ObjectFactory; 031import javolution.util.FastTable; 032import javolution.xml.XMLFormat; 033import javolution.xml.stream.XMLStreamException; 034import org.jscience.mathematics.number.Float64; 035import org.jscience.mathematics.vector.Float64Vector; 036 037/** 038 * A container that holds changeable coordinates of an n-dimensional vector which 039 * indicates direction, but not position. 040 * 041 * <p> Modified by: Joseph A. Huwaldt </p> 042 * 043 * @author Joseph A. Huwaldt, Date: June 13, 2009 044 * @version November 27, 2015 045 * 046 * @param <Q> The Quantity (unit type) of the elements of this vector. 047 */ 048@SuppressWarnings({"serial", "CloneableImplementsClone"}) 049public final class MutableVector<Q extends Quantity> extends GeomVector<Q> { 050 051 // Use an immutable Vector as a backing for the MutableVector. 052 private Vector<Q> _vector; 053 054 /** 055 * Returns a dimensionless <code>MutableVector</code> instance of the specified 056 * dimension with all the coordinate values set to zero. 057 * 058 * @param dim the physical dimension of the vector to create. 059 * @return the vector having the specified dimension and zero meters for values. 060 */ 061 public static MutableVector<Dimensionless> newInstance(int dim) { 062 MutableVector V = FACTORY.object(); 063 V._vector = Vector.newInstance(dim); 064 return V; 065 } 066 067 /** 068 * Returns a <code>MutableVector</code> instance of the specified dimension and units 069 * with all the coordinate values set to zero. 070 * 071 * @param <Q> The Quantity (unit type) of the returned vector. 072 * @param dim the physical dimension of the vector to create. 073 * @param unit the unit in which the coordinates are stated. May not be null. 074 * @return the vector having the specified dimension and zero meters for values. 075 */ 076 public static <Q extends Quantity> MutableVector<Q> newInstance(int dim, Unit<Q> unit) { 077 MutableVector V = FACTORY.object(); 078 V._vector = Vector.newInstance(dim, requireNonNull(unit)); 079 return V; 080 } 081 082 /** 083 * Returns a <code>Vector</code> instance containing the specified GeomVector values. 084 * 085 * @param <Q> The Quantity (unit type) of the returned vector. 086 * @param vector the GeomVector to be placed in a new Vector instance. May not be null. 087 * @return the vector having the specified values. 088 */ 089 public static <Q extends Quantity> MutableVector<Q> valueOf(GeomVector<Q> vector) { 090 MutableVector V = FACTORY.object(); 091 V._vector = vector.immutable(); 092 return V; 093 } 094 095 /** 096 * Returns a dimensionless <code>MutableVector</code> instance holding the specified 097 * <code>double</code> value or values. 098 * 099 * @param x The dimensionless coordinate values. May not be null. 100 * @return the vector having the specified value. 101 */ 102 public static MutableVector<Dimensionless> valueOf(double... x) { 103 MutableVector V = FACTORY.object(); 104 V._vector = Vector.valueOf(requireNonNull(x)); 105 return V; 106 } 107 108 /** 109 * Returns a <code>MutableVector</code> instance holding the specified 110 * <code>double</code> value or values stated in the specified units. 111 * 112 * @param <Q> The Quantity (unit type) of the returned vector. 113 * @param unit the unit in which the coordinates are stated. May not be null. 114 * @param x the coordinate values stated in the specified unit. May not be null. 115 * @return the vector having the specified value. 116 */ 117 public static <Q extends Quantity> MutableVector<Q> valueOf(Unit<Q> unit, double... x) { 118 MutableVector V = FACTORY.object(); 119 V._vector = Vector.valueOf(requireNonNull(unit), requireNonNull(x)); 120 return V; 121 } 122 123 /** 124 * Returns a <code>MutableVector</code> instance containing the specified vector of 125 * Parameter values with compatible units. All the values are converted to the same 126 * units as the 1st value. 127 * 128 * @param <Q> The Quantity (unit type) of the returned vector. 129 * @param vector the vector of Parameter values stated in the specified unit. May not 130 * be null. 131 * @return the vector having the specified values. 132 */ 133 public static <Q extends Quantity> MutableVector<Q> valueOf(org.jscience.mathematics.vector.Vector<Parameter<Q>> vector) { 134 MutableVector V = FACTORY.object(); 135 V._vector = Vector.valueOf(requireNonNull(vector)); 136 return V; 137 } 138 139 /** 140 * Returns a <code>MutableVector</code> instance containing the specified list of 141 * Parameter values with compatible units. All the values are converted to the same 142 * units as the 1st value. 143 * 144 * @param <Q> The Quantity (unit type) of the returned vector. 145 * @param values the list of Parameter values stated in the specified unit. May not be 146 * null. 147 * @return the vector having the specified values. 148 */ 149 public static <Q extends Quantity> MutableVector<Q> valueOf(List<Parameter<Q>> values) { 150 MutableVector<Q> V = FACTORY.object(); 151 V._vector = Vector.valueOf(requireNonNull(values)); 152 return V; 153 } 154 155 /** 156 * Returns a {@link MutableVector} instance containing the specified vector of Float64 157 * values stated in the specified units. 158 * 159 * @param <Q> The Quantity (unit type) of the returned vector. 160 * @param vector the vector of Float64 values stated in the specified unit. May not be 161 * null. 162 * @param unit the unit in which the coordinates are stated. May not be null. 163 * @return the vector having the specified values. 164 */ 165 public static <Q extends Quantity> MutableVector<Q> valueOf(org.jscience.mathematics.vector.Vector<Float64> vector, Unit<Q> unit) { 166 MutableVector V = FACTORY.object(); 167 V._vector = Vector.valueOf(requireNonNull(vector), requireNonNull(unit)); 168 return V; 169 } 170 171 /** 172 * Returns a <code>MutableVector</code> instance holding the specified 173 * <code>Parameter</code> values. All the values are converted to the same units as 174 * the first value. 175 * 176 * @param <Q> The Quantity (unit type) of the returned vector. 177 * @param values A list of values to store in the vector. May not be null. 178 * @return the vector having the specified values in the units of x. 179 */ 180 public static <Q extends Quantity> MutableVector<Q> valueOf(Parameter<Q>... values) { 181 MutableVector V = FACTORY.object(); 182 V._vector = Vector.valueOf(requireNonNull(values)); 183 return V; 184 } 185 186 /** 187 * Returns a <code>MutableVector</code> instance holding the specified 188 * <code>GeomPoint</code> values. 189 * 190 * @param point A point who's coordinates are to be stored in the vector (making it a 191 * position vector). May not be null. 192 * @return the vector having the specified point coordinate values in it. 193 */ 194 public static MutableVector<Length> valueOf(GeomPoint point) { 195 MutableVector V = FACTORY.object(); 196 V._vector = Vector.valueOf(requireNonNull(point)); 197 return V; 198 } 199 200 /** 201 * Returns the number of physical dimensions of this vector. 202 * 203 * @return The number of physical dimensions of this vector. 204 */ 205 @Override 206 public int getPhyDimension() { 207 return _vector.getPhyDimension(); 208 } 209 210 /** 211 * Set the value of a vector dimension to the specified Parameter. 212 * 213 * @param i the dimension index. 214 * @param value The new value of the parameter to set at <code>i</code>. May not be 215 * null. 216 * @throws IndexOutOfBoundsException <code>(i < 0) || (i ≥ getPhyDimension())</code> 217 */ 218 public void set(int i, Parameter<Q> value) { 219 requireNonNull(value); 220 221 // Get a list of values in this point. 222 FastTable<Parameter<Q>> values = FastTable.newInstance(); 223 int size = _vector.getPhyDimension(); 224 for (int j = 0; j < size; ++j) { 225 values.add(_vector.get(j)); 226 } 227 228 // Change the dimension indicated. 229 values.set(i, value); 230 _vector = Vector.valueOf(values); 231 FastTable.recycle(values); 232 233 fireChangeEvent(); // Notify change listeners. 234 } 235 236 /** 237 * Set the value of elements of this vector to the elements of the specified vector. 238 * 239 * @param v The new vector to make this vector equal to. May not be null. 240 * @throws DimensionException <code>(v.getPhyDimension() != getPhyDimension())</code> 241 */ 242 public void set(GeomVector<Q> v) { 243 int numDims = getPhyDimension(); 244 if (v.getPhyDimension() != numDims) 245 throw new DimensionException(RESOURCES.getString("consistantPointDim")); 246 _vector = v.immutable(); 247 } 248 249 /** 250 * Set the value of a vector dimension to the specified double in the current vector 251 * units. 252 * 253 * @param i the dimension index. 254 * @param value The new value of the parameter to set at <code>i</code> in the current 255 * units of this vector. 256 * @throws IndexOutOfBoundsException <code>(i < 0) || (i ≥ getPhyDimension())</code> 257 */ 258 public void setValue(int i, double value) { 259 // Create a Parameter object. 260 Parameter<Q> param = Parameter.valueOf(value, getUnit()); 261 262 // Set the specified dimension to the new parameter object. 263 set(i, param); 264 } 265 266 /** 267 * Returns the value of the Parameter in this vector as a <code>double</code>, stated 268 * in this vector's {@link #getUnit unit}. 269 * 270 * @param i the dimension index. 271 * @return the value of the Parameter at <code>i</code>. 272 * @throws IndexOutOfBoundsException <code>(i < 0) || (i ≥ getPhyDimension())</code> 273 */ 274 @Override 275 public double getValue(int i) { 276 return _vector.getValue(i); 277 } 278 279 /** 280 * Returns the value of the Parameter in this vector as a <code>double</code>, stated 281 * in the specified units. 282 * 283 * @param i the dimension index. 284 * @param unit the unit to return the value in. May not be null. 285 * @return the value of the Parameter at <code>i</code> in the specified unit. 286 * @throws IndexOutOfBoundsException <code>(i < 0) || (i ≥ getPhyDimension())</code> 287 */ 288 @Override 289 public double getValue(int i, Unit<Q> unit) { 290 double value = _vector.getValue(i); 291 Unit<Q> thisUnit = getUnit(); 292 if (unit.equals(thisUnit)) 293 return value; 294 UnitConverter cvtr = Parameter.converterOf(thisUnit, unit); 295 if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary. 296 return value; 297 } 298 return cvtr.convert(value); 299 } 300 301 /** 302 * Set the origin point for this vector. The origin is used as a reference for drawing 303 * the vector and is <i>not</i> a part of the state of this vector and is not used in 304 * any calculations with this vector. 305 * 306 * @param origin The point to set as the origin of this vector. May not be null. 307 */ 308 @Override 309 public void setOrigin(Point origin) { 310 _vector.setOrigin(requireNonNull(origin)); 311 } 312 313 /** 314 * Return the origin point for this vector. 315 * 316 * @return The origin point for this vector. 317 */ 318 @Override 319 public Point getOrigin() { 320 return _vector.getOrigin(); 321 } 322 323 /** 324 * Returns the {@link #norm}, magnitude, or length value of this vector (square root 325 * of the dot product of this vector and itself). 326 * 327 * @return <code>this.norm().getValue()</code>. 328 */ 329 @Override 330 public double normValue() { 331 return _vector.normValue(); 332 } 333 334 /** 335 * Returns the negation of this vector. 336 * 337 * @return <code>-this</code>. 338 */ 339 @Override 340 public Vector<Q> opposite() { 341 return _vector.opposite(); 342 } 343 344 /** 345 * Returns the sum of this vector with the one specified. The unit of the output 346 * vector will be the units of this vector. 347 * 348 * @param that the vector to be added. May not be null. 349 * @return <code>this + that</code>. 350 * @throws DimensionException if vector dimensions are different. 351 */ 352 @Override 353 public Vector<Q> plus(GeomVector<Q> that) { 354 return _vector.plus(that); 355 } 356 357 /** 358 * Returns the sum of this vector with the parameter specified. The input parameter is 359 * added to each component of this vector. The unit of the output vector will be the 360 * units of this vector. 361 * 362 * @param that the parameter to be added to each element of this vector. May not be null. 363 * @return <code>this + that</code>. 364 */ 365 @Override 366 public Vector<Q> plus(Parameter<Q> that) { 367 return _vector.plus(that); 368 } 369 370 /** 371 * Returns the difference between this vector and the one specified. The unit of the 372 * output vector will be the units of this vector. 373 * 374 * @param that the vector to be subtracted from this vector. May not be null. 375 * @return <code>this - that</code>. 376 * @throws DimensionException if vector dimensions are different. 377 */ 378 @Override 379 public Vector<Q> minus(GeomVector<Q> that) { 380 return _vector.minus(that); 381 } 382 383 /** 384 * Subtracts the supplied Parameter from each element of this vector and returns the 385 * result. The unit of the output vector will be the units of this vector. 386 * 387 * @param that the Parameter to be subtracted from each element of this vector. May 388 * not be null. 389 * @return <code>this - that</code>. 390 */ 391 @Override 392 public Vector<Q> minus(Parameter<Q> that) { 393 return _vector.minus(that); 394 } 395 396 /** 397 * Returns the product of this vector with the specified coefficient (dimensionless). 398 * 399 * @param k the coefficient multiplier. 400 * @return <code>this · k</code> 401 */ 402 @Override 403 public Vector<Q> times(double k) { 404 return _vector.times(k); 405 } 406 407 /** 408 * Returns the product of this vector with the specified coefficient. 409 * 410 * @param k the coefficient multiplier. May not be null. 411 * @return <code>this · k</code> 412 */ 413 @Override 414 public Vector<? extends Quantity> times(Parameter<?> k) { 415 return _vector.times(k); 416 } 417 418 /** 419 * Returns the dot product (scalar product) of this vector with the one specified. 420 * 421 * @param that the vector multiplier. May not be null. 422 * @return <code>this · that</code> 423 * @throws DimensionException if <code>this.dimension() != that.dimension()</code> 424 * @see <a href="http://en.wikipedia.org/wiki/Dot_product"> 425 * Wikipedia: Dot Product</a> 426 */ 427 @Override 428 public Parameter<? extends Quantity> times(GeomVector<?> that) { 429 return _vector.times(that); 430 } 431 432 /** 433 * Returns the element-by-element product of this vector with the one specified. 434 * 435 * @param that the vector multiplier. May not be null. 436 * @return <code>this .* that</code> 437 * @throws DimensionException if <code>this.dimension() != that.dimension()</code> 438 */ 439 @Override 440 public Vector<? extends Quantity> timesEBE(GeomVector<?> that) { 441 return _vector.timesEBE(that); 442 } 443 444 /** 445 * Returns the cross product of two vectors. 446 * 447 * @param that the vector multiplier. May not be null. 448 * @return <code>this x that</code> 449 * @throws DimensionException if 450 * <code>(that.getDimension() != this.getDimension())</code> 451 * @see <a href="http://en.wikipedia.org/wiki/Cross_product"> 452 * Wikipedia: Cross Product</a> 453 */ 454 @Override 455 public Vector<? extends Quantity> cross(GeomVector<?> that) { 456 return _vector.cross(that); 457 } 458 459 /** 460 * Returns this vector with each element divided by the specified divisor 461 * (dimensionless). 462 * 463 * @param divisor the divisor. 464 * @return <code>this / divisor</code>. 465 */ 466 @Override 467 public Vector<Q> divide(double divisor) { 468 return _vector.divide(divisor); 469 } 470 471 /** 472 * Returns this vector with each element divided by the specified divisor. 473 * 474 * @param divisor the divisor. May not be null. 475 * @return <code>this / divisor</code>. 476 */ 477 @Override 478 public Vector<? extends Quantity> divide(Parameter<?> divisor) { 479 return _vector.divide(divisor); 480 } 481 482 /** 483 * Return an immutable version of this vector. 484 * 485 * @return An immutable version of this vector. 486 */ 487 @Override 488 public Vector<Q> immutable() { 489 return _vector; 490 } 491 492 /** 493 * Returns this vector converted to a unit vector by dividing all the vector's 494 * elements by the length ({@link #norm}) of this vector. 495 * 496 * @return This vector converted to a unit vector. 497 */ 498 @Override 499 public Vector<Dimensionless> toUnitVector() { 500 return _vector.toUnitVector(); 501 } 502 503 /** 504 * Returns the unit in which the {@link #getValue values} in this vector are stated 505 * in. 506 * 507 * @return The unit in which the values in this vector are stated. 508 */ 509 @Override 510 public Unit getUnit() { 511 return _vector.getUnit(); 512 } 513 514 /** 515 * Returns the equivalent to this vector but stated in the specified unit. 516 * 517 * @param unit the unit of the vector to be returned. May not be null. 518 * @return an equivalent to this vector but stated in the specified unit. 519 * @throws ConversionException if the the input unit is not compatible with this unit. 520 */ 521 @Override 522 public MutableVector to(Unit unit) throws ConversionException { 523 if (unit.equals(getUnit())) 524 return this; 525 MutableVector V = FACTORY.object(); 526 V._vector = this._vector.to(unit); 527 return V; 528 } 529 530 /** 531 * Return a copy of this vector converted to the specified number of physical 532 * dimensions. If the number of dimensions is greater than this element, then zeros 533 * are added to the additional dimensions. If the number of dimensions is less than 534 * this element, then the extra dimensions are simply dropped (truncated). If the new 535 * dimensions are the same as the dimension of this element, then this element is 536 * simply returned. 537 * 538 * @param newDim The dimension of the vector to return. 539 * @return A copy of this vector converted to the new dimensions. 540 */ 541 @Override 542 public MutableVector<Q> toDimension(int newDim) { 543 if (newDim < 1) 544 throw new IllegalArgumentException(RESOURCES.getString("vectorDimGT0")); 545 int thisDim = this.getPhyDimension(); 546 if (newDim == thisDim) 547 return this; 548 549 MutableVector<Q> V = FACTORY.object(); 550 V._vector = this._vector.toDimension(newDim); 551 552 return V; 553 } 554 555 /** 556 * Returns a copy of this Vector instance 557 * {@link javolution.context.AllocatorContext allocated} by the calling thread 558 * (possibly on the stack). 559 * 560 * @return an identical and independent copy of this vector. 561 */ 562 @Override 563 public MutableVector<Q> copy() { 564 return copyOf(this); 565 } 566 567 /** 568 * Return a copy of this object with any transformations or subranges removed 569 * (applied). 570 * 571 * @return A copy of this object with any transformations or subranges removed. 572 */ 573 @Override 574 public Vector<Q> copyToReal() { 575 return Vector.valueOf(_vector); 576 } 577 578 /** 579 * Returns a <code>ParameterVector</code> representation of this vector. 580 * 581 * @return A ParameterVector that is equivalent to this vector. 582 */ 583 @Override 584 public ParameterVector<Q> toParameterVector() { 585 return _vector.toParameterVector(); 586 } 587 588 /** 589 * Returns a <code>Float64Vector</code> containing the elements of this vector stated 590 * in the current units. 591 * 592 * @return A Float64Vector that contains the elements of this vector in the current 593 * units. 594 */ 595 @Override 596 public Float64Vector toFloat64Vector() { 597 return _vector.toFloat64Vector(); 598 } 599 600 /** 601 * Compares this vector against the specified object for strict equality (same values 602 * and same units). 603 * 604 * @param obj the object to compare with. 605 * @return <code>true</code> if this vector is identical to that vector; 606 * <code>false</code> otherwise. 607 */ 608 @Override 609 public boolean equals(Object obj) { 610 if (this == obj) 611 return true; 612 if ((obj == null) || (obj.getClass() != this.getClass())) 613 return false; 614 615 MutableVector that = (MutableVector)obj; 616 return this._vector.equals(that._vector) 617 && super.equals(obj); 618 } 619 620 /** 621 * Returns the hash code for this parameter. 622 * 623 * @return the hash code value. 624 */ 625 @Override 626 public int hashCode() { 627 return 31*super.hashCode() + Objects.hash(_vector); 628 } 629 630 /** 631 * Recycles a <code>MutableVector</code> instance immediately (on the stack when 632 * executing in a <code>StackContext</code>). 633 * 634 * @param instance The instance to be recycled. 635 */ 636 public static void recycle(MutableVector instance) { 637 FACTORY.recycle(instance); 638 } 639 640 /** 641 * Holds the default XML representation for this object. 642 */ 643 @SuppressWarnings("FieldNameHidesFieldInSuperclass") 644 protected static final XMLFormat<MutableVector> XML = new XMLFormat<MutableVector>(MutableVector.class) { 645 646 @Override 647 public MutableVector newInstance(Class<MutableVector> cls, InputElement xml) throws XMLStreamException { 648 return FACTORY.object(); 649 } 650 651 @Override 652 public void read(InputElement xml, MutableVector obj) throws XMLStreamException { 653 654 Unit unit = Unit.valueOf(xml.getAttribute("unit")); 655 if (!(Length.UNIT.isCompatible(unit) || Dimensionless.UNIT.isCompatible(unit))) 656 throw new XMLStreamException( 657 MessageFormat.format(RESOURCES.getString("incompatibleUnits"), 658 "MutableVector", "length")); 659 660 GeomVector.XML.read(xml, obj); // Call parent read. 661 662 FastTable<Float64> valueList = FastTable.newInstance(); 663 while (xml.hasNext()) { 664 Float64 value = xml.getNext(); 665 valueList.add(value); 666 } 667 668 obj._vector = Vector.valueOf(Float64Vector.valueOf(valueList), unit); 669 670 } 671 672 @Override 673 public void write(MutableVector obj, OutputElement xml) throws XMLStreamException { 674 GeomVector.XML.write(obj, xml); // Call parent write. 675 676 xml.setAttribute("unit", obj.getUnit().toString()); 677 int size = obj._vector.getPhyDimension(); 678 for (int i = 0; i < size; ++i) 679 xml.add(Float64.valueOf(obj._vector.getValue(i))); 680 681 } 682 }; 683 684 /////////////////////// 685 // Factory creation. // 686 /////////////////////// 687 private MutableVector() { } 688 689 @SuppressWarnings("unchecked") 690 private static final ObjectFactory<MutableVector> FACTORY = new ObjectFactory<MutableVector>() { 691 @Override 692 protected MutableVector create() { 693 return new MutableVector(); 694 } 695 696 @Override 697 protected void cleanup(MutableVector obj) { 698 obj.reset(); 699 } 700 }; 701 702 @SuppressWarnings("unchecked") 703 private static <Q extends Quantity> MutableVector<Q> copyOf(MutableVector<Q> original) { 704 MutableVector<Q> V = FACTORY.object(); 705 V._vector = original._vector.copy(); 706 original.copyState(V); 707 return V; 708 } 709}