001/** 002 * PointVehicle -- A list of PointComponent objects. 003 * 004 * Copyright (C) 2009-2025, by Joseph A. Huwaldt. All rights reserved. 005 * 006 * This library is free software; you can redistribute it and/or 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 Library 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 java.text.MessageFormat; 021import java.util.Collection; 022import static java.util.Objects.requireNonNull; 023import javax.measure.converter.ConversionException; 024import javax.measure.quantity.Length; 025import javax.measure.unit.Unit; 026import javolution.context.ObjectFactory; 027import javolution.util.FastTable; 028import javolution.xml.XMLFormat; 029import javolution.xml.stream.XMLStreamException; 030 031/** 032 * A list that holds only {@link PointComponent} objects. 033 * <p> 034 * WARNING: This list allows geometry to be stored in different units. If consistent units 035 * are required, then the user must specifically convert the list items. 036 * </p> 037 * 038 * <p> Modified by: Joseph A. Huwaldt </p> 039 * 040 * @author Joseph A. Huwaldt, Date: May 1, 2009 041 * @version February 17, 2025 042 */ 043@SuppressWarnings({"serial", "CloneableImplementsClone"}) 044public final class PointVehicle extends AbstractPointGeomList<PointVehicle, PointComponent> { 045 046 private FastTable<PointComponent> _list; 047 048 /** 049 * Return the list underlying this geometry list. 050 * 051 * @return The list underlying this geometry list. 052 */ 053 @Override 054 protected FastTable<PointComponent> getList() { 055 return _list; 056 } 057 058 /** 059 * Returns a new, empty, preallocated or recycled <code>PointVehicle</code> 060 * instance (on the stack when executing in a <code>StackContext</code>), 061 * that can store a list of {@link PointComponent} objects. 062 * 063 * @return A new, empty PointVehicle. 064 */ 065 public static PointVehicle newInstance() { 066 PointVehicle list = FACTORY.object(); 067 list._list = FastTable.newInstance(); 068 return list; 069 } 070 071 /** 072 * Returns a new, empty, preallocated or recycled <code>PointVehicle</code> 073 * instance (on the stack when executing in a <code>StackContext</code>) 074 * with the specified name, that can store a list of {@link PointComponent} 075 * objects. 076 * 077 * @param name The name to be assigned to this list (may be <code>null</code>). 078 * @return A new, empty PointVehicle. 079 */ 080 public static PointVehicle newInstance(String name) { 081 PointVehicle list = PointVehicle.newInstance(); 082 list.setName(name); 083 return list; 084 } 085 086 /** 087 * Return a PointVehicle made up of the {@link PointComponent} objects in 088 * the specified collection. 089 * 090 * @param name The name to be assigned to this list (may be <code>null</code>). 091 * @param elements A collection of PointComponent elements. May not be null. 092 * @return A new PointVehicle containing the elements in the specified collection. 093 */ 094 public static PointVehicle valueOf(String name, Collection<? extends PointComponent> elements) { 095 for (Object element : elements) { 096 requireNonNull(element, RESOURCES.getString("collectionElementsNullErr")); 097 if (!(element instanceof PointComponent)) 098 throw new ClassCastException(MessageFormat.format( 099 RESOURCES.getString("listElementTypeErr"), "PointVehicle", "PointComponent")); 100 } 101 102 PointVehicle list = PointVehicle.newInstance(name); 103 list.addAll(elements); 104 105 return list; 106 } 107 108 /** 109 * Return a PointVehicle made up of the {@link PointComponent} objects in 110 * the specified array. 111 * 112 * @param name The name to be assigned to this list (may be <code>null</code>). 113 * @param elements A array of PointComponent elements. May not be null. 114 * @return A new PointVehicle containing the elements in the specified array. 115 */ 116 public static PointVehicle valueOf(String name, PointComponent... elements) { 117 requireNonNull(elements); 118 PointVehicle list = PointVehicle.newInstance(name); 119 list.addAll(elements); 120 121 return list; 122 } 123 124 /** 125 * Return a PointVehicle made up of the {@link PointComponent} objects in 126 * the specified list. 127 * 128 * @param elements A list of PointComponent elements. May not be null. 129 * @return A new PointVehicle containing the elements in the specified array. 130 */ 131 public static PointVehicle valueOf(PointComponent... elements) { 132 return PointVehicle.valueOf(null, elements); 133 } 134 135 /** 136 * Returns the range of elements in this list from the specified start and 137 * ending indexes. 138 * 139 * @param first index of the first element to return (0 returns the 1st 140 * element, -1 returns the last, etc). 141 * @param last index of the last element to return (0 returns the 1st 142 * element, -1 returns the last, etc). 143 * @return the list of elements in the given range from this list. 144 * @throws IndexOutOfBoundsException if the given index is out of range: 145 * <code>index ≥ size()</code> 146 */ 147 @Override 148 public PointVehicle getRange(int first, int last) { 149 first = normalizeIndex(first); 150 last = normalizeIndex(last); 151 152 PointVehicle list = PointVehicle.newInstance(); 153 for (int i=first; i <= last; ++i) 154 list.add(get(i)); 155 return list; 156 } 157 158 /** 159 * Returns an new {@link PointVehicle} with the elements in this list in 160 * reverse order. 161 * 162 * @return A new PointVehicle with the elements in this list in reverse order. 163 */ 164 @Override 165 public PointVehicle reverse() { 166 PointVehicle list = PointVehicle.newInstance(); 167 copyState(list); 168 int size = this.size(); 169 for (int i=size-1; i >= 0; --i) 170 list.add(get(i)); 171 return list; 172 } 173 174 /** 175 * Return the equivalent of this list converted to the specified number of 176 * physical dimensions. If the number of dimensions is greater than this 177 * element, then zeros are added to the additional dimensions. If the number 178 * of dimensions is less than this element, then the extra dimensions are 179 * simply dropped (truncated). If the new dimensions are the same as the 180 * dimension of this element, then this list is simply returned. 181 * 182 * @param newDim The dimension of the element to return. 183 * @return The equivalent of this list converted to the new dimensions. 184 */ 185 @Override 186 public PointVehicle toDimension(int newDim) { 187 if (getPhyDimension() == newDim) 188 return this; 189 PointVehicle newList = PointVehicle.newInstance(); 190 copyState(newList); 191 int size = this.size(); 192 for (int i=0; i < size; ++i) { 193 PointComponent element = this.get(i); 194 newList.add(element.toDimension(newDim)); 195 } 196 return newList; 197 } 198 199 /** 200 * Returns the equivalent to this list but with <I>all</I> the elements stated in the 201 * specified unit. 202 * 203 * @param unit the length unit of the list to be returned. May not be null. 204 * @return an equivalent to this list but stated in the specified unit. 205 * @throws ConversionException if the the input unit is not a length unit. 206 */ 207 @Override 208 public PointVehicle to(Unit<Length> unit) { 209 requireNonNull(unit); 210 PointVehicle list = PointVehicle.newInstance(); 211 copyState(list); 212 int size = this.size(); 213 for (int i=0; i < size; ++i) { 214 PointComponent e = this.get(i); 215 list.add(e.to(unit)); 216 } 217 return list; 218 } 219 220 /** 221 * Returns a copy of this <code>PointVehicle</code> instance 222 * {@link javolution.context.AllocatorContext allocated} by the calling 223 * thread (possibly on the stack). 224 * 225 * @return an identical and independent copy of this object. 226 */ 227 @Override 228 public PointVehicle copy() { 229 return copyOf(this); 230 } 231 232 /** 233 * Return a copy of this object with any transformations or subranges 234 * removed (applied). 235 * 236 * @return A copy of this list with any sub-element transformations or 237 * subranges removed. 238 */ 239 @Override 240 public PointVehicle copyToReal() { 241 PointVehicle newList = PointVehicle.newInstance(); 242 copyState(newList); 243 int size = this.size(); 244 for (int i=0; i < size; ++i) { 245 PointComponent element = this.get(i); 246 newList.add(element.copyToReal()); 247 } 248 return newList; 249 } 250 251 /** 252 * Return the total number of quadrilateral panels in this vehicle. 253 * 254 * @return the total number of panels in this vehicle. 255 * @throws IndexOutOfBoundsException if the strings in any array in this 256 * vehicle have different lengths. 257 */ 258 public int getNumberOfPanels() throws IndexOutOfBoundsException { 259 int sum = 0; 260 int size = this.size(); 261 for (int i=0; i < size; ++i) { 262 PointComponent e = this.get(i); 263 sum += e.getNumberOfPanels(); 264 } 265 return sum; 266 } 267 268 /** 269 * Returns transformed version of this element. The returned object 270 * implements {@link GeomTransform} and contains transformed versions of the 271 * contents of this list as children. 272 * 273 * @param transform The transform to apply to this geometry element. May not be null. 274 * @return A transformed version of this geometry element. 275 * @throws DimensionException if this element is not 3D. 276 */ 277 @Override 278 public PointVehicle getTransformed(GTransform transform) { 279 requireNonNull(transform); 280 PointVehicle list = PointVehicle.newInstance(); 281 copyState(list); 282 int size = this.size(); 283 for (int i=0; i < size; ++i) { 284 PointComponent element = this.get(i); 285 list.add(element.getTransformed(transform)); 286 } 287 return list; 288 } 289 290 /** 291 * Replaces the {@link PointComponent} at the specified position in this list with the 292 * specified element. Null elements are ignored. The input element must have the same 293 * physical dimensions as the other items in this list, or an exception is thrown. 294 * 295 * @param index The index of the element to replace (0 returns the 1st element, -1 296 * returns the last, -2 returns the 2nd from last, etc). 297 * @param element The element to be stored at the specified position. 298 * <code>null</code> elements are ignored. 299 * @return The element previously at the specified position in this list. May not be 300 * null. 301 * @throws java.lang.IndexOutOfBoundsException - if <code>index > size()</code> 302 * @throws DimensionException if the input element's dimensions are different from 303 * this list's dimensions. 304 */ 305 @Override 306 public PointComponent set(int index, PointComponent element) { 307 return super.set(index, requireNonNull(element)); 308 } 309 310 /** 311 * Inserts the specified {@link PointComponent} at the specified position in this 312 * list. Shifts the element currently at that position (if any) and any subsequent 313 * elements to the right (adds one to their indices). Null values are ignored. The 314 * input value must have the same physical dimensions as the other items in this list, 315 * or an exception is thrown. 316 * <p> 317 * Note: If this method is used concurrent access must be synchronized (the list is 318 * not thread-safe). 319 * </p> 320 * 321 * @param index the index at which the specified element is to be inserted. (0 returns 322 * the 1st element, -1 returns the last, -2 returns the 2nd from last, 323 * etc). 324 * @param value the element to be inserted. May not be null. 325 * @throws IndexOutOfBoundsException if <code>index > size()</code> 326 * @throws DimensionException if the input value dimensions are different from 327 * this list's dimensions. 328 */ 329 @Override 330 public void add(int index, PointComponent value) { 331 super.add(index, requireNonNull(value)); 332 } 333 334 /** 335 * Inserts all of the {@link PointComponent} objects in the specified collection into 336 * this list at the specified position. Shifts the element currently at that position 337 * (if any) and any subsequent elements to the right (increases their indices). The 338 * new elements will appear in this list in the order that they are returned by the 339 * specified collection's iterator. The behavior of this operation is unspecified if 340 * the specified collection is modified while the operation is in progress. Note that 341 * this will occur if the specified collection is this list, and it's nonempty. The 342 * input elements must have the same physical dimensions as the other items in this 343 * list, or an exception is thrown. 344 * 345 * @param index index at which to insert first element from the specified collection. 346 * @param c Elements to be inserted into this collection. May not be null. 347 * @return <code>true</code> if this collection changed as a result of the call. 348 * @throws DimensionException if the input element's dimensions are different from 349 * this list's dimensions. 350 */ 351 @Override 352 public boolean addAll(int index, Collection<? extends PointComponent> c) { 353 int thisSize = this.size(); 354 for (Object element : c) { 355 requireNonNull(element, RESOURCES.getString("collectionElementsNullErr")); 356 if (!(element instanceof PointComponent)) 357 throw new ClassCastException(MessageFormat.format( 358 RESOURCES.getString("listElementTypeErr"), "PointVehicle", "PointComponent")); 359 if (thisSize != 0) { 360 if (((GeomElement)element).getPhyDimension() != this.getPhyDimension()) 361 throw new DimensionException(RESOURCES.getString("dimensionErr")); 362 } 363 } 364 return super.addAll(index, c); 365 } 366 367 /** 368 * Holds the default XML representation for this object. 369 */ 370 @SuppressWarnings("FieldNameHidesFieldInSuperclass") 371 protected static final XMLFormat<PointVehicle> XML = new XMLFormat<PointVehicle>(PointVehicle.class) { 372 373 @Override 374 public PointVehicle newInstance(Class<PointVehicle> cls, XMLFormat.InputElement xml) throws XMLStreamException { 375 PointVehicle obj = PointVehicle.newInstance(); 376 return obj; 377 } 378 379 @Override 380 public void read(XMLFormat.InputElement xml, PointVehicle obj) throws XMLStreamException { 381 AbstractPointGeomList.XML.read(xml, obj); // Call parent read. 382 } 383 384 @Override 385 public void write(PointVehicle obj, XMLFormat.OutputElement xml) throws XMLStreamException { 386 AbstractPointGeomList.XML.write(obj, xml); // Call parent write. 387 } 388 }; 389 390 ////////////////////// 391 // Factory Creation // 392 ////////////////////// 393 private static final ObjectFactory<PointVehicle> FACTORY = new ObjectFactory<PointVehicle>() { 394 @Override 395 protected PointVehicle create() { 396 return new PointVehicle(); 397 } 398 399 @Override 400 protected void cleanup(PointVehicle obj) { 401 obj.reset(); 402 } 403 }; 404 405 /** 406 * Recycles a case instance immediately (on the stack when executing in a 407 * StackContext). 408 * 409 * @param instance The instance to be recycled. 410 */ 411 public static void recycle(PointVehicle instance) { 412 FACTORY.recycle(instance); 413 } 414 415 /** 416 * Do not allow the default constructor to be used except by subclasses. 417 */ 418 protected PointVehicle() { } 419 420 private static PointVehicle copyOf(PointVehicle original) { 421 PointVehicle o = PointVehicle.newInstance(); 422 original.copyState(o); 423 int size = original.size(); 424 for (int i=0; i < size; ++i) { 425 PointComponent element = original.get(i); 426 o.add(element.copy()); 427 } 428 return o; 429 } 430}