001/** 002 * PointArray -- A collection of PointString objects that make up a "list of strings" or 003 * an "array of points". 004 * 005 * Copyright (C) 2003-2025, by 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 Library 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.Parameter; 022import java.text.MessageFormat; 023import java.util.Collection; 024import static java.util.Objects.requireNonNull; 025import javax.measure.converter.ConversionException; 026import javax.measure.quantity.Area; 027import javax.measure.quantity.Length; 028import javax.measure.unit.NonSI; 029import javax.measure.unit.Unit; 030import javolution.context.ObjectFactory; 031import javolution.context.StackContext; 032import javolution.util.FastTable; 033import javolution.xml.XMLFormat; 034import javolution.xml.XMLReferenceResolver; 035import javolution.xml.stream.XMLStreamException; 036 037/** 038 * A <code>PointArray</code> is a collection of {@link PointString} objects that make up a 039 * "list of strings of points". Any number of strings may be added to an array. All the 040 * strings in an array must have the same dimensions. In order to draw the array, all the 041 * strings in a array must also have the same number of points. 042 * <p> 043 * WARNING: This list allows geometry to be stored in different units. If consistent units 044 * are required, then the user must specifically convert the list items. 045 * </p> 046 * 047 * <p> Modified by: Joseph A. Huwaldt </p> 048 * 049 * @author Joseph A. Huwaldt, Date: March 5, 2003 050 * @version February 17, 2025 051 * 052 * @param <E> The type of GeomPoint stored in this array of points. 053 */ 054@SuppressWarnings({"serial", "CloneableImplementsClone"}) 055public final class PointArray<E extends GeomPoint> extends AbstractPointGeomList<PointArray<E>, PointString<E>> { 056 057 private FastTable<PointString<E>> _list; 058 059 /** 060 * Return the list underlying this geometry list. 061 * 062 * @return The list underlying this geometry list. 063 */ 064 @Override 065 protected FastTable<PointString<E>> getList() { 066 return _list; 067 } 068 069 /** 070 * Returns a new, empty, preallocated or recycled <code>PointArray</code> 071 * instance (on the stack when executing in a <code>StackContext</code>), 072 * that can store a list of {@link PointString} objects. 073 * 074 * @return A new, empty PointArray 075 */ 076 public static PointArray newInstance() { 077 PointArray list = FACTORY.object(); 078 list._list = FastTable.newInstance(); 079 return list; 080 } 081 082 /** 083 * Returns a new, preallocated or recycled <code>PointArray</code> instance 084 * (on the stack when executing in a <code>StackContext</code>) with the 085 * specified name, that can store a list of {@link PointString} objects. 086 * 087 * @param name The name to be assigned to this list (may be <code>null</code>). 088 * @return A new, empty PointArray 089 */ 090 public static PointArray newInstance(String name) { 091 PointArray list = PointArray.newInstance(); 092 list.setName(name); 093 return list; 094 } 095 096 /** 097 * Return a PointArray made up of the {@link PointString} objects in the 098 * specified collection. 099 * 100 * @param <E> The type of GeomPoint stored in this array of points. 101 * @param name The name to be assigned to this list (may be <code>null</code>). 102 * @param elements A collection that contains a set of strings. May not be null. 103 * @return A new PointArray containing the elements in the specified collection. 104 */ 105 public static <E extends GeomPoint> PointArray<E> valueOf(String name, Collection<? extends PointString<E>> elements) { 106 for (Object element : elements) { 107 requireNonNull(element, RESOURCES.getString("collectionElementsNullErr")); 108 if (!(element instanceof PointString)) 109 throw new ClassCastException(MessageFormat.format( 110 RESOURCES.getString("listElementTypeErr"), "PointArray", "PointString")); 111 } 112 113 PointArray<E> list = PointArray.newInstance(name); 114 list.addAll(elements); 115 116 return list; 117 } 118 119 /** 120 * Return a PointArray made up of the {@link PointString} objects in the 121 * specified array. 122 * 123 * @param <E> The type of GeomPoint stored in this array of points. 124 * @param name The name to be assigned to this string (may be <code>null</code>). 125 * @param elements A list that contains a set of strings. May not be null. 126 * @return A new PointArray containing the elements in the specified array. 127 */ 128 public static <E extends GeomPoint> PointArray<E> valueOf(String name, PointString<E>... elements) { 129 requireNonNull(elements); 130 PointArray<E> list = PointArray.newInstance(name); 131 list.addAll(elements); 132 133 return list; 134 } 135 136 /** 137 * Return a PointArray made up of the {@link PointString} objects in the 138 * specified array. 139 * 140 * @param <E> The type of GeomPoint stored in this array of points. 141 * @param elements A list that contains a set of strings. May not be null. 142 * @return A new PointArray containing the elements in the specified array. 143 */ 144 public static <E extends GeomPoint> PointArray<E> valueOf(PointString<E>... elements) { 145 return PointArray.valueOf(null, elements); 146 } 147 148 /** 149 * Returns the {@link GeomPoint} at the specified pair of indices in this 150 * array. This is a convenience method that is identical to 151 * <code>array.get(row).get(col)</code>. 152 * 153 * @param row The row (string or "T") index of the panel to be returned 154 * @param col The column (point in a string or "S") index of the panel to be returned 155 * @return The point at the specified row and column in this array. 156 * @throws IndexOutOfBoundsException if there the specified indices do not 157 * exist in this array. 158 */ 159 public E get(int row, int col) throws IndexOutOfBoundsException { 160 return this.get(row).get(col); 161 } 162 163 /** 164 * Return a column of points from this array as a new PointString object. A column is 165 * made up of a point from each string of the array. 166 * 167 * @param col The column of points to return. 168 * @return A new PointString object containing the points from the specified column of 169 * this array. 170 * @throws IndexOutOfBoundsException if there the specified index does not exist in 171 * this array. 172 */ 173 public PointString<E> getColumn(int col) throws IndexOutOfBoundsException { 174 PointString<E> output = PointString.newInstance(); 175 int size = size(); 176 for (int row = 0; row < size; ++row) { 177 output.add(get(row).get(col)); 178 } 179 return output; 180 } 181 182 /** 183 * Returns the range of elements in this list from the specified start and 184 * ending indexes. 185 * 186 * @param first index of the first element to return (0 returns the 1st 187 * element, -1 returns the last, etc). 188 * @param last index of the last element to return (0 returns the 1st 189 * element, -1 returns the last, etc). 190 * @return the list of elements in the given range from this list. 191 * @throws IndexOutOfBoundsException if the given index is out of range: 192 * <code>index ≥= size()</code> 193 */ 194 @Override 195 public PointArray<E> getRange(int first, int last) { 196 first = normalizeIndex(first); 197 last = normalizeIndex(last); 198 199 PointArray<E> list = PointArray.newInstance(); 200 for (int i = first; i <= last; ++i) 201 list.add(get(i)); 202 return list; 203 } 204 205 /** 206 * Returns an new {@link PointArray} with the elements in this list in 207 * reverse order. 208 * 209 * @return A new PointArray with the elements in this list in reverse order. 210 * This reverses the rows of the array. 211 */ 212 @Override 213 public PointArray<E> reverse() { 214 PointArray<E> list = PointArray.newInstance(); 215 copyState(list); 216 int size = this.size(); 217 for (int i = size - 1; i >= 0; --i) { 218 list.add(get(i)); 219 } 220 return list; 221 } 222 223 /** 224 * Returns an new {@link PointArray} with the points in each string in this 225 * array in reverse order. 226 * 227 * @return A new PointArray with the points in each string in reverse order. 228 * This reverses the columns of the array. 229 */ 230 public PointArray<E> reverseStrings() { 231 PointArray<E> list = PointArray.newInstance(); 232 copyState(list); 233 int size = this.size(); 234 for (int i = 0; i < size; ++i) { 235 PointString<E> str = this.get(i); 236 list.add(str.reverse()); 237 } 238 return list; 239 } 240 241 /** 242 * Returns a new {@link PointArray} that is the transpose this array (rows 243 * and columns swapped). This method can only be called if all the strings 244 * in this array have the same number of points in them. 245 * 246 * @return A new PointArray that is the transpose of this array. 247 * @throws IndexOutOfBoundsException if the number of points is not the same 248 * in each string in this array. 249 */ 250 public PointArray<E> transpose() throws IndexOutOfBoundsException { 251 252 // Check for string consistancy in this array. 253 checkStringConsistancy(); 254 255 // Build up the transposed array. 256 PointArray<E> arr = PointArray.newInstance(); 257 copyState(arr); 258 int numStrings = size(); 259 int numPointsPerString = get(0).size(); 260 for (int i = 0; i < numPointsPerString; ++i) { 261 PointString<E> str = PointString.newInstance(); 262 for (int j = 0; j < numStrings; ++j) 263 str.add(this.get(j).get(i)); 264 arr.add(str); 265 } 266 267 return arr; 268 } 269 270 /** 271 * Returns a new {@link PointArray} that is identical to this array but with every 272 * other row (string of points) and column (points in the strings) removed. The 1st 273 * row and column and the last row and column are always retained. If there are less 274 * than 3 columns in the array, then a new array is returned that contains the same 275 * columns as this array. If there are less than 3 rows, then a new array is returned 276 * that contains the same rows as this array. 277 * 278 * @return A new PointArray identical to this array, but with every other row and 279 * column removed. 280 */ 281 public PointArray<E> thin() { 282 PointArray<E> arr1 = thinRows(); 283 PointArray<E> arr2 = arr1.thinColumns(); 284 PointArray.recycle(arr1); 285 return arr2; 286 } 287 288 /** 289 * Returns a new {@link PointArray} that is identical to this array but with every 290 * other row (string of points) removed. The 1st row (index = 0) and last row (index = 291 * size()-1) are always retained. If there are less than 3 rows in the array, then a 292 * new array is returned that contains the same rows as this array. 293 * 294 * @return A new PointArray that is identical to this array but with every other row 295 * removed. 296 */ 297 public PointArray<E> thinRows() { 298 PointArray<E> list = PointArray.newInstance(); 299 copyState(list); 300 301 int size = size(); 302 if (size < 3) { 303 list.addAll(this); 304 return list; 305 } 306 307 int sizem1 = size - 1; 308 for (int i = 0; i < sizem1; i += 2) { 309 list.add(get(i)); 310 } 311 list.add(get(size - 1)); 312 313 return list; 314 } 315 316 /** 317 * Returns a new {@link PointArray} that is identical to this array but with every 318 * other column (points in strings) removed. The 1st column (index = 0) and last 319 * column (index = get(0).size()-1) are always retained. If there are less than 3 320 * columns in the array, then a new array is returned that contains the same columns 321 * as this array. 322 * 323 * @return A new PointArray that is identical to this array, but with every other 324 * column (points in the strings) removed. 325 * @throws IndexOutOfBoundsException if the number of points is not the same in each 326 * string in this array. 327 */ 328 public PointArray<E> thinColumns() throws IndexOutOfBoundsException { 329 330 // Check for string consistancy in this array. 331 checkStringConsistancy(); 332 333 PointArray<E> list = PointArray.newInstance(); 334 copyState(list); 335 336 int size = this.size(); 337 for (int i = 0; i < size; ++i) { 338 PointString<E> str = this.get(i); 339 list.add(str.thin()); 340 } 341 342 return list; 343 } 344 345 /** 346 * Returns a new {@link PointArray} that is identical to this array but with new rows 347 * (strings of points) and columns (points in each string) of points linearly 348 * interpolated between each of the existing rows and columns. If there are less than 349 * 2 columns in the array, then a new array is returned that contains the one column 350 * in this array. If there are less than 2 points in each string of the array, then a 351 * new array is returned that contains the one point in each string in this array. 352 * 353 * @return A new PointArray with new rows and columns linearly interpolated between 354 * each of the existing rows and columns. 355 * @throws IndexOutOfBoundsException if the number of points is not the same in each 356 * string in this array. 357 */ 358 public PointArray<E> enrich() throws IndexOutOfBoundsException { 359 PointArray<E> arr1 = enrichColumns(); 360 PointArray<E> arr2 = arr1.enrichRows(); 361 PointArray.recycle(arr1); 362 return arr2; 363 } 364 365 /** 366 * Returns a new {@link PointArray} that is identical to this array but with 367 * a new row (string of points) linearly interpolated between each of the existing 368 * rows. If there are less than 2 rows in the array, then a new array 369 * is returned that contains the one row in this array. 370 * 371 * @return A new PointArray with new rows linearly interpolated between 372 * each of the existing rows. 373 * @throws IndexOutOfBoundsException if the number of points is not the same 374 * in each string in this array. 375 */ 376 public PointArray<E> enrichRows() throws IndexOutOfBoundsException { 377 378 // Check for string consistancy in this array. 379 checkStringConsistancy(); 380 381 PointArray list = PointArray.newInstance(); 382 copyState(list); 383 384 int size = size(); 385 if (size < 2) { 386 list.add(get(0)); 387 return list; 388 } 389 390 PointString<? extends GeomPoint> str1 = get(0); 391 list.add(str1); 392 int numPnts = str1.size(); // Number of points in each string. 393 394 for (int i = 1; i < size; ++i) { 395 PointString<? extends GeomPoint> str2 = get(i); 396 PointString stra = PointString.newInstance(); 397 for (int j = 0; j < numPnts; ++j) { 398 GeomPoint p1 = str1.get(j); 399 GeomPoint p2 = str2.get(j); 400 Point pa = p1.plus(p2).divide(2); // Calculate the average point. 401 stra.add(pa); 402 } 403 list.add(stra); 404 list.add(str2); 405 str1 = str2; 406 } 407 408 return list; 409 } 410 411 /** 412 * Returns a new {@link PointArray} that is identical to this array but with 413 * a new column (point) linearly interpolated between each point of the existing 414 * strings. If there are less than 2 points in each string of the array, 415 * then a new array is returned that contains the one point in each string 416 * in this array. 417 * 418 * @return A new PointArray with new column linearly interpolated between 419 * each of the existing columns. 420 * @throws IndexOutOfBoundsException if the number of points is not the same 421 * in each string in this array. 422 */ 423 public PointArray<E> enrichColumns() throws IndexOutOfBoundsException { 424 425 // Check for string consistancy in this array. 426 checkStringConsistancy(); 427 428 PointArray list = PointArray.newInstance(); 429 copyState(list); 430 431 int size = this.size(); 432 for (int i = 0; i < size; ++i) { 433 PointString str = this.get(i); 434 list.add(str.enrich()); 435 } 436 437 return list; 438 } 439 440 /** 441 * Return a TriangleList containing a simple triangulation of the input array of 442 * quadrilateral panels. The input panels are triangulated by dividing each quad, 443 * formed by two adjacent strings of points, into two triangles. Any subranges or 444 * transforms on the input points is lost (using copyToReal()) by this triangulation. 445 * 446 * @return A new TriangleList containing a triangulation of the this array of 447 * quadrilateral panels. 448 * @see #copyToReal() 449 */ 450 public TriangleList<Triangle> triangulate() { 451 return TriangleList.triangulateQuads(this); 452 } 453 454 /** 455 * Return the equivalent of this list converted to the specified number of 456 * physical dimensions. If the number of dimensions is greater than this 457 * element, then zeros are added to the additional dimensions. If the number 458 * of dimensions is less than this element, then the extra dimensions are 459 * simply dropped (truncated). If the new dimensions are the same as the 460 * dimension of this element, then this list is simply returned. 461 * 462 * @param newDim The dimension of the element to return. 463 * @return The equivalent of this list converted to the new dimensions. 464 */ 465 @Override 466 public PointArray<E> toDimension(int newDim) { 467 if (getPhyDimension() == newDim) 468 return this; 469 PointArray<E> newList = PointArray.newInstance(); 470 copyState(newList); 471 int size = this.size(); 472 for (int i = 0; i < size; ++i) { 473 PointString element = this.get(i); 474 newList.add(element.toDimension(newDim)); 475 } 476 return newList; 477 } 478 479 /** 480 * Returns the equivalent to this list but with <I>all</I> the elements stated in the 481 * specified unit. 482 * 483 * @param unit the length unit of the list to be returned. May not be null. 484 * @return an equivalent to this list but stated in the specified unit. 485 * @throws ConversionException if the the input unit is not a length unit. 486 */ 487 @Override 488 public PointArray to(Unit<Length> unit) { 489 requireNonNull(unit); 490 PointArray list = PointArray.newInstance(); 491 copyState(list); 492 int size = this.size(); 493 for (int i = 0; i < size; ++i) { 494 PointString e = this.get(i); 495 list.add(e.to(unit)); 496 } 497 return list; 498 } 499 500 /** 501 * Returns a copy of this <code>PointArray</code> instance 502 * {@link javolution.context.AllocatorContext allocated} by the calling 503 * thread (possibly on the stack). 504 * 505 * @return an identical and independent copy of this object. 506 */ 507 @Override 508 public PointArray<E> copy() { 509 return copyOf(this); 510 } 511 512 /** 513 * Return a copy of this object with any transformations or subranges 514 * removed (applied). 515 * 516 * @return A copy of this list with any sub-element transformations or 517 * subranges removed. 518 */ 519 @Override 520 public PointArray copyToReal() { 521 PointArray newList = PointArray.newInstance(); 522 copyState(newList); 523 int size = this.size(); 524 for (int i = 0; i < size; ++i) { 525 PointString element = this.get(i); 526 newList.add(element.copyToReal()); 527 } 528 return newList; 529 } 530 531 /** 532 * Return the total number of quadrilateral panels in this array of points. 533 * 534 * @return the total number of panels in this array. 535 * @throws IndexOutOfBoundsException if the strings in this array have 536 * different lengths. 537 */ 538 public int getNumberOfPanels() throws IndexOutOfBoundsException { 539 int numStrings = size(); 540 if (numStrings < 2) 541 return 0; 542 543 // Check for string consistancy in this array. 544 checkStringConsistancy(); 545 546 int numPointsPerString = get(0).size(); 547 if (numPointsPerString < 2) 548 return 0; 549 550 return (numStrings - 1) * (numPointsPerString - 1); 551 } 552 553 /** 554 * Return the total surface area of all the panels formed by this array of 555 * points. 556 * 557 * @return The total surface area of all the panels formed by this array of 558 * points. 559 */ 560 public Parameter<Area> getArea() { 561 // Break the array up into triangle strips and sum the area of all the triangles. 562 // This code is essentially a repeat of TriangleList.getArea(), but is faster 563 // since it doesn't create as much garbage. 564 565 StackContext.enter(); 566 try { 567 // Check for degenerate cases. 568 Unit<Area> areaUnit = getUnit().pow(2).asType(Area.class); 569 Parameter<Area> area = Parameter.ZERO_AREA.to(areaUnit); 570 int numStr = size(); 571 if (numStr < 2) 572 return StackContext.outerCopy(area); 573 int numPnts = get(0).size(); 574 if (numPnts < 2) 575 return StackContext.outerCopy(area); 576 577 int numPntsm1 = numPnts - 1; 578 int numStrm1 = numStr - 1; 579 for (int i = 0; i < numStrm1; ++i) { 580 PointString<E> str1 = get(i); 581 PointString<E> str2 = get(i + 1); 582 for (int j = 0; j < numPntsm1; ++j) { 583 GeomPoint p1 = str1.get(j); 584 GeomPoint p2 = str1.get(j + 1); 585 GeomPoint p3 = str2.get(j); 586 GeomPoint p4 = str2.get(j + 1); 587 588 // Triange #1 589 Parameter<Length> a = p1.distance(p2); 590 Parameter<Length> b = p2.distance(p4); 591 Parameter<Area> dA = a.times(b).asType(Area.class); 592 area = area.plus(dA); 593 594 // Triange #2 595 a = p3.distance(p4); 596 b = p3.distance(p1); 597 dA = a.times(b).asType(Area.class); 598 area = area.plus(dA); 599 } 600 } 601 602 return StackContext.outerCopy(area.times(0.5)); 603 604 } finally { 605 StackContext.exit(); 606 } 607 } 608 609 /** 610 * Returns transformed version of this element. The returned object 611 * implements {@link GeomTransform} and contains transformed versions of the 612 * contents of this list as children. 613 * 614 * @param transform The transform to apply to this geometry element. May not be null. 615 * @return A transformed version of this geometry element. 616 * @throws DimensionException if this element is not 3D. 617 */ 618 @Override 619 public PointArray getTransformed(GTransform transform) { 620 requireNonNull(transform); 621 PointArray list = PointArray.newInstance(); 622 copyState(list); 623 int size = this.size(); 624 for (int i = 0; i < size; ++i) { 625 PointString element = this.get(i); 626 list.add(element.getTransformed(transform)); 627 } 628 return list; 629 } 630 631 /** 632 * Replaces the {@link PointString} at the specified position in this list with the 633 * specified element. Null elements are ignored. The input element must have the same 634 * physical dimensions as the other items in this list, or an exception is thrown. 635 * 636 * @param index The index of the element to replace (0 returns the 1st element, -1 637 * returns the last, -2 returns the 2nd from last, etc). 638 * @param element The element to be stored at the specified position. 639 * <code>null</code> elements are ignored. 640 * @return The element previously at the specified position in this list. May not be 641 * null. 642 * @throws java.lang.IndexOutOfBoundsException - if <code>index > size()</code> 643 * @throws DimensionException if the input element's dimensions are different from 644 * this list's dimensions. 645 */ 646 @Override 647 public PointString<E> set(int index, PointString<E> element) { 648 return super.set(index, requireNonNull(element)); 649 } 650 651 /** 652 * Inserts the specified {@link PointString} at the specified position in this list. 653 * Shifts the element currently at that position (if any) and any subsequent elements 654 * to the right (adds one to their indices). Null values are ignored. The input 655 * value must have the same physical dimensions as the other items in this list, or 656 * an exception is thrown. 657 * <p> 658 * Note: If this method is used concurrent access must be synchronized (the list is 659 * not thread-safe). 660 * </p> 661 * 662 * @param index the index at which the specified element is to be inserted. (0 returns 663 * the 1st element, -1 returns the last, -2 returns the 2nd from last, 664 * etc). 665 * @param value the element to be inserted. May not be null. 666 * @throws IndexOutOfBoundsException if <code>index > size()</code> 667 * @throws DimensionException if the input value dimensions are different from 668 * this list's dimensions. 669 */ 670 @Override 671 public void add(int index, PointString<E> value) { 672 super.add(index, requireNonNull(value)); 673 } 674 675 /** 676 * Inserts all of the {@link PointString} objects in the specified collection into 677 * this list at the specified position. Shifts the element currently at that position 678 * (if any) and any subsequent elements to the right (increases their indices). The 679 * new elements will appear in this list in the order that they are returned by the 680 * specified collection's iterator. The behavior of this operation is unspecified if 681 * the specified collection is modified while the operation is in progress. Note that 682 * this will occur if the specified collection is this list, and it's nonempty. The 683 * input elements must have the same physical dimensions as the other items in this 684 * list, or an exception is thrown. 685 * 686 * @param index index at which to insert first element from the specified collection. 687 * @param c elements to be inserted into this collection. May not be null. 688 * @return <code>true</code> if this collection changed as a result of the call. 689 * @throws DimensionException if the input element's dimensions are different from 690 * this list's dimensions. 691 */ 692 @Override 693 public boolean addAll(int index, Collection<? extends PointString<E>> c) { 694 int thisSize = this.size(); 695 for (Object element : c) { 696 requireNonNull(element, RESOURCES.getString("collectionElementsNullErr")); 697 if (!(element instanceof PointString)) 698 throw new ClassCastException(MessageFormat.format( 699 RESOURCES.getString("listElementTypeErr"), "PointArray", "PointString")); 700 if (thisSize != 0) { 701 if (((GeomElement)element).getPhyDimension() != this.getPhyDimension()) 702 throw new DimensionException(RESOURCES.getString("dimensionErr")); 703 } 704 } 705 return super.addAll(index, c); 706 } 707 708 /** 709 * Determines if each string in this array has the same number of points and 710 * throws an exception if they do not. 711 */ 712 private void checkStringConsistancy() throws IndexOutOfBoundsException { 713 714 FastTable<PointString<E>> tlist = getList(); 715 int numPointsPerString = tlist.get(0).size(); 716 int numStrings = tlist.size(); 717 for (int i = 0; i < numStrings; ++i) { 718 PointString str = tlist.get(i); 719 if (str.size() != numPointsPerString) 720 throw new IndexOutOfBoundsException( 721 MessageFormat.format(RESOURCES.getString("arrStringSizeErr"), i)); 722 } 723 724 } 725 726 /** 727 * Holds the default XML representation for this object. 728 */ 729 @SuppressWarnings("FieldNameHidesFieldInSuperclass") 730 protected static final XMLFormat<PointArray> XML = new XMLFormat<PointArray>(PointArray.class) { 731 732 @Override 733 public PointArray newInstance(Class<PointArray> cls, XMLFormat.InputElement xml) throws XMLStreamException { 734 PointArray obj = PointArray.newInstance(); 735 return obj; 736 } 737 738 @Override 739 public void read(XMLFormat.InputElement xml, PointArray obj) throws XMLStreamException { 740 AbstractPointGeomList.XML.read(xml, obj); // Call parent read. 741 } 742 743 @Override 744 public void write(PointArray obj, XMLFormat.OutputElement xml) throws XMLStreamException { 745 AbstractPointGeomList.XML.write(obj, xml); // Call parent write. 746 } 747 }; 748 749 ////////////////////// 750 // Factory Creation // 751 ////////////////////// 752 private static final ObjectFactory<PointArray> FACTORY = new ObjectFactory<PointArray>() { 753 @Override 754 protected PointArray create() { 755 return new PointArray(); 756 } 757 758 @Override 759 protected void cleanup(PointArray obj) { 760 obj.reset(); 761 } 762 }; 763 764 /** 765 * Recycles a case instance immediately (on the stack when executing in a 766 * StackContext). 767 * 768 * @param instance The instance to be recycled. 769 */ 770 public static void recycle(PointArray instance) { 771 FACTORY.recycle(instance); 772 } 773 774 /** 775 * Do not allow the default constructor to be used except by subclasses. 776 */ 777 protected PointArray() { 778 } 779 780 private static <E2 extends GeomPoint> PointArray<E2> copyOf(PointArray<E2> original) { 781 PointArray<E2> o = PointArray.newInstance(); 782 original.copyState(o); 783 int size = original.size(); 784 for (int i = 0; i < size; ++i) { 785 PointString<E2> element = original.get(i); 786 o.add(element.copy()); 787 } 788 return o; 789 } 790 791 /** 792 * Tests the methods in this class. 793 * 794 * @param args Command-line arguments (ignored). 795 */ 796 public static void main(String args[]) { 797 System.out.println("Testing PointArray:"); 798 799 Point p1 = Point.valueOf(0, 0, 0, NonSI.FOOT); 800 Point p2 = Point.valueOf(1, 0, 0, NonSI.FOOT); 801 Point p3 = Point.valueOf(2, 0, 0, NonSI.FOOT); 802 Point p4 = Point.valueOf(3, 0, 0, NonSI.FOOT); 803 PointString str1 = PointString.valueOf("String 1", p1, p2, p3, p4); 804 System.out.println("str1 = " + str1); 805 806 GTransform T1 = GTransform.newTranslation(Vector.valueOf(NonSI.FOOT, 0, 1, 0)); 807 PointString str2 = str1.getTransformed(T1); 808 str2.setName("String 2"); 809 System.out.println("str2 = " + str2); 810 811 PointString str3 = str2.getTransformed(T1); 812 str3.setName("String 3"); 813 System.out.println("str3 = " + str3); 814 815 PointString str4 = str3.getTransformed(T1); 816 str4.setName("String 4"); 817 System.out.println("str4 = " + str4); 818 819 PointArray arr1 = PointArray.valueOf("An array", str1, str2, str3, str4); 820 System.out.println("arr1 = " + arr1); 821 System.out.println("arr1.getPhyDimension() = " + arr1.getPhyDimension()); 822 System.out.println("arr1.size() = " + arr1.size()); 823 824 System.out.println("arr1.getBoundsMin() = " + arr1.getBoundsMin()); 825 System.out.println("arr1.getBoundsMax() = " + arr1.getBoundsMax()); 826 827 GTransform T2 = GTransform.newRotationX(Parameter.valueOf(90, NonSI.DEGREE_ANGLE)); 828 PointArray arr2 = arr1.getTransformed(T2); 829 System.out.println("\nRotate about X by 90 deg:"); 830 System.out.println("arr2 = " + arr2); 831 System.out.println("arr2.getBoundsMin() = " + arr2.getBoundsMin()); 832 System.out.println("arr2.getBoundsMax() = " + arr2.getBoundsMax()); 833 834 // Write out XML data. 835 try { 836 System.out.println(); 837 838 // Creates some useful aliases for class names. 839 javolution.xml.XMLBinding binding = new GeomXMLBinding(); 840 841 javolution.xml.XMLObjectWriter writer = javolution.xml.XMLObjectWriter.newInstance(System.out); 842 writer.setIndentation(" "); 843 writer.setBinding(binding); 844 writer.setReferenceResolver(new XMLReferenceResolver()); // Enables cross-references. 845 writer.write(arr1, "PointArray", PointArray.class); 846 writer.flush(); 847 848 System.out.println(); 849 } catch (Exception e) { 850 e.printStackTrace(); 851 } 852 853 } 854 855}