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