001 package edu.nrao.sss.measure; 002 003 import static edu.nrao.sss.math.MathUtil.MC_FINAL_CALC; 004 005 import java.math.BigDecimal; 006 import java.math.RoundingMode; 007 008 import javax.xml.bind.annotation.XmlAccessType; 009 import javax.xml.bind.annotation.XmlAccessorType; 010 import javax.xml.bind.annotation.XmlElement; 011 import javax.xml.bind.annotation.XmlType; 012 013 import edu.nrao.sss.math.MathUtil; 014 import edu.nrao.sss.util.StringUtil; 015 016 /** 017 * A measure of linear velocity. 018 * <p> 019 * <b>Version Info:</b> 020 * <table style="margin-left:2em"> 021 * <tr><td>$Revision: 1707 $</td></tr> 022 * <tr><td>$Date $</td></tr> 023 * <tr><td>$Author: dharland $</td></tr> 024 * </table></p> 025 * 026 * @author David M. Harland 027 * @since 2006-05-30 028 */ 029 @XmlAccessorType(XmlAccessType.NONE) 030 @XmlType(propOrder= {"xmlValue","unitsSymbol"}) 031 public class LinearVelocity 032 implements Cloneable, Comparable<LinearVelocity> 033 { 034 private static final BigDecimal DEFAULT_VALUE = BigDecimal.ZERO; 035 private static final LinearVelocityUnits DEFAULT_UNITS = 036 LinearVelocityUnits.KILOMETERS_PER_SECOND; 037 038 //Used by equals, hashCode, and compareTo methods 039 private static LinearVelocityUnits STD_UNITS = 040 LinearVelocityUnits.KILOMETERS_PER_SECOND; 041 042 private static final int PRECISION = MC_FINAL_CALC.getPrecision(); 043 044 private BigDecimal value; 045 private LinearVelocityUnits units; 046 047 //=========================================================================== 048 // CONSTRUCTORS 049 //=========================================================================== 050 051 /** Creates a new linear velocity of zero kilometers per second. */ 052 public LinearVelocity() 053 { 054 set(DEFAULT_VALUE, DEFAULT_UNITS); 055 } 056 057 /** 058 * Creates a new velocity of {@code kms} kilometers per second. 059 * See {@link #setValue(BigDecimal)} for information 060 * about valid parameter values and exceptions that might 061 * be thrown. 062 * 063 * @param kms the magnitude of this velocity in kilometers per second. 064 */ 065 public LinearVelocity(BigDecimal kms) 066 { 067 set(kms, LinearVelocityUnits.KILOMETERS_PER_SECOND); 068 } 069 070 /** 071 * Creates a new velocity of {@code kms} kilometers per second. 072 * See {@link #setValue(BigDecimal)} for information 073 * about valid parameter values and exceptions that might 074 * be thrown. 075 * 076 * @param kms the magnitude of this velocity in kilometers per second. 077 */ 078 public LinearVelocity(String kms) 079 { 080 set(kms, LinearVelocityUnits.KILOMETERS_PER_SECOND); 081 } 082 083 /** 084 * Creates a new linear velocity with the given magnitude and units. 085 * See {@link #set(BigDecimal, LinearVelocityUnits)} for information 086 * about valid parameter values and exceptions that might 087 * be thrown. 088 * 089 * @param value the magnitude of this velocity. 090 * 091 * @param units the units in which {@code value} is expressed. 092 */ 093 public LinearVelocity(BigDecimal value, LinearVelocityUnits units) 094 { 095 set(value, units); 096 } 097 098 /** 099 * Creates a new linear velocity with the given magnitude and units. 100 * See {@link #set(BigDecimal, LinearVelocityUnits)} for information 101 * about valid parameter values and exceptions that might 102 * be thrown. 103 * 104 * @param value the magnitude of this velocity. 105 * 106 * @param units the units in which {@code value} is expressed. 107 */ 108 public LinearVelocity(String value, LinearVelocityUnits units) 109 { 110 set(value, units); 111 } 112 113 /** 114 * Resets this linear velocity so that it is equal to one created 115 * via the no-argument constructor. 116 */ 117 public void reset() 118 { 119 set(DEFAULT_VALUE, DEFAULT_UNITS); 120 } 121 122 //=========================================================================== 123 // GETTING & SETTING THE PROPERTIES 124 //=========================================================================== 125 126 /** 127 * Returns the magnitude of this linear velocity. 128 * @return the magnitude of this linear velocity. 129 */ 130 public BigDecimal getValue() 131 { 132 return value; 133 } 134 135 /** 136 * Returns the units of this linear velocity. 137 * @return the units of this linear velocity. 138 */ 139 public LinearVelocityUnits getUnits() 140 { 141 return units; 142 } 143 144 /** 145 * Sets the value and units of this velocity based on {@code velocityText}. 146 * See {@link #parse(String)} for the expected format of 147 * {@code velocityText}. 148 * <p> 149 * If the parsing fails, this velocity will be kept in its current 150 * state.</p> 151 * 152 * @param velocityText 153 * a string that will be converted into a velocity. 154 * 155 * @throws IllegalArgumentException 156 * if {@code velocityText} is not in the expected form. 157 * 158 * @since 2008-09-22 159 */ 160 public void set(String velocityText) 161 { 162 if (velocityText == null || velocityText.equals("")) 163 { 164 this.reset(); 165 } 166 else 167 { 168 LinearVelocityUnits oldUnits = units; 169 BigDecimal oldValue = value; 170 171 try { 172 this.parseVelocity(velocityText); 173 } 174 catch (Exception ex) { 175 set(oldValue, oldUnits); 176 throw new IllegalArgumentException("Could not parse " + velocityText, ex); 177 } 178 } 179 } 180 181 /** 182 * Sets the magnitude and units of this linear velocity. 183 * <p> 184 * See {@link #setValue(BigDecimal)} for more information on legal 185 * values for <tt>value</tt>.</p> 186 * 187 * @param value the new magnitude of this linear velocity. 188 * @param units the units in which {@code value} is expressed. 189 */ 190 public final void set(BigDecimal value, LinearVelocityUnits units) 191 { 192 setValue(value); 193 setUnits(units); 194 } 195 196 /** 197 * Sets the magnitude and units of this linear velocity. 198 * <p> 199 * See {@link #setValue(String)} for more information on legal 200 * values for <tt>value</tt>.</p> 201 * 202 * @param value the new magnitude of this linear velocity. 203 * @param units the units in which {@code value} is expressed. 204 */ 205 public final void set(String value, LinearVelocityUnits units) 206 { 207 setValue(value); 208 setUnits(units); 209 } 210 211 /** 212 * Sets the magnitude of this linear velocity to {@code newValue}. 213 * <p> 214 * Note that the <tt>units</tt> of this velocity are unaffected by 215 * this method.</p> 216 * 217 * @param newValue 218 * the new magnitude for this linear velocity. 219 * This value may not be <i>null</i> but may be negative or infinite. 220 * 221 * @throws NumberFormatException 222 * if {@code newValue} is <i>null</i>. 223 */ 224 public final void setValue(BigDecimal newValue) 225 { 226 if (newValue == null) 227 throw new NumberFormatException("newValue=" + newValue + 228 " is not a valid linear velocity. It must be non-null."); 229 230 setAndRescale(newValue); 231 } 232 233 /** 234 * Sets the magnitude of this linear velocity to {@code newValue}. 235 * <p> 236 * Note that the <tt>units</tt> of this velocity are unaffected by 237 * this method.</p> 238 * 239 * @param newValue 240 * the new magnitude for this linear velocity. 241 * This value may not be <i>null</i> but may be negative or infinite. 242 * The allowable representations of infinity are 243 * <tt>"infinity", "+infinity", </tt>and<tt> "-infinity"</tt>; 244 * these values are not case sensitive. 245 * 246 * @throws NumberFormatException 247 * if {@code newValue} is <i>null</i>. 248 */ 249 public final void setValue(String newValue) 250 { 251 if (newValue == null) 252 throw new NumberFormatException("newValue may not be null."); 253 254 BigDecimal newBD; 255 256 newValue = newValue.trim().toLowerCase(); 257 258 if (newValue.equals("infinity") || 259 newValue.equals("+infinity") || newValue.equals("-infinity")) 260 { 261 newBD = MathUtil.getInfiniteValue(newValue.startsWith("-") ? -1 : +1); 262 } 263 else 264 { 265 newBD = new BigDecimal(newValue); 266 } 267 268 setAndRescale(newBD); 269 } 270 271 private void setAndRescale(BigDecimal newValue) 272 { 273 int precision = newValue.precision(); 274 275 if (precision < PRECISION) 276 { 277 int newScale = 278 (newValue.signum() == 0) ? 1 : PRECISION - precision + newValue.scale(); 279 280 value = newValue.setScale(newScale); 281 } 282 else if (precision > PRECISION) 283 { 284 value = newValue.round(MC_FINAL_CALC); 285 } 286 else 287 { 288 value = newValue; 289 } 290 } 291 292 /** 293 * Sets the units of this linear velocity to {@code newUnits}. 294 * <p> 295 * Note that the <tt>value</tt> of this linear velocity is unaffected by 296 * this method. Contrast this with {@link #convertTo(LinearVelocityUnits)}.</p> 297 * 298 * @param newUnits the new units for this linear velocity. If {@code newUnits} is 299 * <i>null</i> it will be treated as a default type. 300 */ 301 public final void setUnits(LinearVelocityUnits newUnits) 302 { 303 units = (newUnits == null) ? LinearVelocityUnits.getDefault() : newUnits; 304 } 305 306 //=========================================================================== 307 // HELPERS FOR PERSISTENCE MECHANISMS 308 //=========================================================================== 309 310 //JAXB was having trouble with the overloaded setValue methods. 311 //These methods work around that trouble. 312 @XmlElement(name="value") 313 @SuppressWarnings("unused") 314 private BigDecimal getXmlValue() { return getValue().stripTrailingZeros(); } 315 @SuppressWarnings("unused") 316 private void setXmlValue(BigDecimal v) { setValue(v); } 317 318 //We'll use the shorter symbol for persistent storage 319 @XmlElement(name="units") 320 @SuppressWarnings("unused") 321 private String getUnitsSymbol() { return getUnits().getSymbol(); } 322 @SuppressWarnings("unused") 323 private void setUnitsSymbol(String u) { setUnits(LinearVelocityUnits.fromString(u)); } 324 325 //=========================================================================== 326 // DERIVED QUERIES 327 //=========================================================================== 328 329 /** 330 * Returns <i>true</i> if this velocity is in its default state, 331 * no matter how it got there. 332 * <p> 333 * A velocity is in its <i>default state</i> if both its value and 334 * its units are the same as those of a velocity newly created via 335 * the {@link #LinearVelocity() no-argument constructor}. 336 * A velocity whose most recent update came via the 337 * {@link #reset() reset} method is also in its default state.</p> 338 * 339 * @return <i>true</i> if this velocity is in its default state. 340 */ 341 public boolean isInDefaultState() 342 { 343 return (value == DEFAULT_VALUE) && 344 units.equals(DEFAULT_UNITS); 345 } 346 347 /** 348 * Returns <i>true</i> if this velocity is infinite. 349 * @return <i>true</i> if this velocity is infinite. 350 */ 351 public boolean isInfinite() 352 { 353 return MathUtil.doubleValueIsInfinite(value); 354 } 355 356 //=========================================================================== 357 // CONVERSION TO, AND EXPRESSION IN, OTHER UNITS 358 //=========================================================================== 359 360 /** 361 * Converts this measure of linear velocity to the new units. 362 * <p> 363 * After this method is complete this linear velocity will have units of 364 * {@code newUnits} and its <tt>value</tt> will have been converted 365 * accordingly.</p> 366 * 367 * @param newUnits the new units for this linear velocity. 368 * If {@code newUnits} is <i>null</i> an 369 * {@code IllegalArgumentException} will be thrown. 370 * 371 * @return this linear velocity. The reason for this return type is to allow 372 * code of this nature: 373 * {@code double kms = 374 * myLinearVelocity.convertTo( 375 * LinearVelocityUnits.KILOMETERS_PER_SECOND).getValue();} 376 */ 377 public LinearVelocity convertTo(LinearVelocityUnits newUnits) 378 { 379 if (newUnits == null) 380 throw new 381 IllegalArgumentException("NULL is not a valid value for newUnits."); 382 383 if (!newUnits.equals(units)) 384 { 385 set(toUnits(newUnits), newUnits); 386 } 387 388 return this; 389 } 390 391 /** 392 * Returns the magnitude of this linear velocity in {@code otherUnits}. 393 * <p> 394 * Note that this method does not alter the state of this linear velocity. 395 * Contrast this with {@link #convertTo(LinearVelocityUnits)}.</p> 396 * 397 * @param otherUnits the units in which to express this linear velocity's 398 * magnitude. 399 * 400 * @return this linear velocity's value converted to {@code otherUnits}. 401 * 402 * @throws IllegalArgumentException if {@code otherUnits} is <i>null</i>. 403 */ 404 public BigDecimal toUnits(LinearVelocityUnits otherUnits) 405 { 406 if (otherUnits == null) 407 throw new IllegalArgumentException("May not convert to NULL units."); 408 409 BigDecimal answer = value; 410 411 //No conversion for zero, infinite, or if no change of units 412 if (!otherUnits.equals(units) && 413 value.signum() != 0 && !isInfinite()) 414 { 415 answer = units.convertTo(otherUnits, value); 416 } 417 418 return answer; 419 } 420 421 //=========================================================================== 422 // ARITHMETIC 423 //=========================================================================== 424 425 /** 426 * Adds {@code other} linear velocity to this one. 427 * 428 * @param other the linear velocity to be added to this linear velocity. 429 * 430 * @return this linear velocity, after the addition. 431 */ 432 public LinearVelocity add(LinearVelocity other) 433 { 434 //TODO when we work on INFINITY, we need to consider other being infinite 435 // and the result being inf, too 436 if (!isInfinite()) 437 setAndRescale(value.add(other.toUnits(this.units))); 438 439 return this; 440 } 441 442 /** 443 * Subtracts {@code other} linear velocity from this one. 444 * 445 * @param other the linear velocity to be subtracted from this angular velocity. 446 * 447 * @return this linear velocity, after the subtraction. 448 */ 449 public LinearVelocity subtract(LinearVelocity other) 450 { 451 //TODO when we work on INFINITY, we need to consider other being infinite 452 // and the result being inf, too 453 if (!isInfinite()) 454 setAndRescale(value.subtract(other.toUnits(this.units))); 455 456 return this; 457 } 458 459 /** 460 * Multiplies this velocity by {@code multiplier}. 461 * 462 * @param multiplier the number by which this velocity should be multiplied. 463 * 464 * @return this velocity, after the multiplication. 465 */ 466 public LinearVelocity multiplyBy(BigDecimal multiplier) 467 { 468 if (!isInfinite()) 469 setAndRescale(value.multiply(multiplier)); 470 471 return this; 472 } 473 474 /** 475 * Divides this velocity by {@code divisor}. 476 * 477 * @param divisor the number by which this velocity should be divided. 478 * 479 * @return this velocity, after the division. 480 */ 481 public LinearVelocity divideBy(BigDecimal divisor) 482 { 483 //TODO deal w/ infinity here 484 setAndRescale(value.divide(divisor, RoundingMode.HALF_UP)); 485 486 return this; 487 } 488 489 //=========================================================================== 490 // PARSING 491 //=========================================================================== 492 493 /** 494 * Returns a new velocity based on {@code velocityString}. 495 * <p> 496 * <b><u>Valid Formats</u></b><br/> 497 * Let R be the text representation of a real number.<br/> 498 * Let w represent zero or more whitespace characters.<br/> 499 * Let S be a valid {@link LinearVelocityUnits units} symbol.<br/> 500 * <br/> 501 * <i>Format One</i>: <tt>wRw</tt>. The given number will be defined to be 502 * in units of {@link LinearVelocityUnits#KILOMETERS_PER_SECOND km/s}.<br/> 503 * <br/> 504 * <i>Format Two</i>: <tt>wRwSw</tt>.</p> 505 * 506 * @param velocityString a string that will be converted into 507 * a velocity. 508 * 509 * @return a new velocity. 510 * 511 * @throws IllegalArgumentException if {@code velocityString} is not in 512 * the expected form. 513 */ 514 public static LinearVelocity parse(String velocityString) 515 { 516 LinearVelocity newVelocity = new LinearVelocity(); 517 518 //null & "" are permissible 519 if ((velocityString != null) && !velocityString.equals("")) 520 { 521 try 522 { 523 newVelocity.parseVelocity(velocityString); 524 } 525 catch (Exception ex) 526 { 527 throw new IllegalArgumentException("Could not parse " + velocityString + 528 ". " + ex.getMessage(), ex); 529 } 530 } 531 532 return newVelocity; 533 } 534 535 //Did not just look for alpha char in case we have wacky things 536 //like Greeks symbols (eg, micrometers). 537 //Want 1st char that is non-digit, non-space, and not in [+ - .]. 538 static final String VALUE_UNITS_SPLITTER = "[^\\+\\-\\.\\d\\s]"; 539 540 /** 541 * If parsing was successful, this velocity's units & value will have been 542 * valued. Otherwise an exception is thrown. 543 */ 544 private void parseVelocity(String velocityString) 545 { 546 //Quick exit if text represents infinity 547 if (parseInfiniteVelocity(velocityString)) 548 return; 549 550 String[] parts = velocityString.split(VALUE_UNITS_SPLITTER, 2); 551 552 if (parts.length == 1) 553 { 554 set(parts[0], LinearVelocityUnits.getDefault()); 555 } 556 else if (parts.length == 2) 557 { 558 String unitsText = velocityString.substring(parts[0].length()); 559 LinearVelocityUnits vu = LinearVelocityUnits.fromString(unitsText); 560 561 if (vu == null) 562 throw new IllegalArgumentException("Could not parse '" + velocityString + 563 "'. Software thinks your units are '" + unitsText + 564 "', but supports no such units."); 565 566 set(parts[0], vu); 567 } 568 else 569 { 570 throw new RuntimeException("PROGRAMMER ERROR: split velocityString '" + 571 velocityString + "' into " + parts.length + 572 " parts. Max expected is 2 parts."); 573 } 574 } 575 576 //TODO see if this can be generalized in EnumUtil, perhaps 577 // This code is also in AngularVelocity 578 /** Returns <i>true</i> if parsed velocity was infinite. */ 579 private boolean parseInfiniteVelocity(String velocText) 580 { 581 final String origText = velocText; //in case we need to throw exception 582 583 boolean isInfinite; 584 585 final String INF_TEXT = "infinity"; 586 587 char signChar = velocText.charAt(0); 588 boolean negate = (signChar == '-'); 589 boolean hasSignChar = negate || (signChar == '+'); 590 591 //Strip off "+" or "-" 592 if (hasSignChar) 593 velocText = velocText.substring(1); 594 595 int testLength = INF_TEXT.length(); 596 int actualLength = velocText.length(); 597 598 //Might have "infinity" with no units 599 if (actualLength == testLength) 600 { 601 isInfinite = velocText.equalsIgnoreCase(INF_TEXT); 602 603 if (isInfinite) 604 set(MathUtil.getInfiniteValue(negate ? -1 : +1), STD_UNITS); 605 } 606 //Might have "infinity" followed by units 607 else if (actualLength > testLength) 608 { 609 String testString = velocText.substring(0, testLength); 610 611 isInfinite = testString.equalsIgnoreCase(INF_TEXT); 612 613 if (isInfinite) 614 { 615 LinearVelocityUnits vu = 616 LinearVelocityUnits.fromString(velocText.substring(testLength, actualLength)); 617 618 if (vu == null) 619 throw new IllegalArgumentException("Could not parse '" + origText + 620 "'. This looked like an infinite velocity but units could not be determined."); 621 622 set(MathUtil.getInfiniteValue(negate ? -1 : +1), vu); 623 } 624 } 625 //String too short to hold "infinity" 626 else //actualLength < testLength 627 { 628 isInfinite = false; 629 } 630 631 return isInfinite; 632 } 633 634 //=========================================================================== 635 // UTILITY METHODS 636 //=========================================================================== 637 638 /** Returns a text representation of this linear velocity. */ 639 public String toString() 640 { 641 return StringUtil.getInstance().formatNoScientificNotation(getValue()) + 642 getUnits().getSymbol(); 643 } 644 645 /** 646 * Returns a text representation of this velocity. 647 * 648 * @param minFracDigits the minimum number of places after the decimal point. 649 * 650 * @param maxFracDigits the maximum number of places after the decimal point. 651 * 652 * @return a text representation of this velocity. 653 */ 654 public String toString(int minFracDigits, int maxFracDigits) 655 { 656 return StringUtil.getInstance().formatNoScientificNotation(getValue(), 657 minFracDigits, 658 maxFracDigits) + 659 getUnits().getSymbol(); 660 } 661 662 /** Returns a linear velocity that is equal to this one. */ 663 public LinearVelocity clone() 664 { 665 //Since this class has only primitive (& immutable) attributes, 666 //the clone in Object is all we need. 667 try 668 { 669 return (LinearVelocity)super.clone(); 670 } 671 catch (CloneNotSupportedException ex) 672 { 673 //We'll never get here, but just in case... 674 throw new RuntimeException(ex); 675 } 676 } 677 678 /** Returns <i>true</i> if {@code o} is equal to this linear velocity. */ 679 public boolean equals(Object o) 680 { 681 //Quick exit if o is this 682 if (o == this) 683 return true; 684 685 //Quick exit if o is null 686 if (o == null) 687 return false; 688 689 //Quick exit if classes are different 690 if (!o.getClass().equals(this.getClass())) 691 return false; 692 693 LinearVelocity other = (LinearVelocity)o; 694 695 //Treat two infinite values of same sign as equal, 696 //regardless of actual BigDecimal values 697 if (isInfinite() && other.isInfinite()) 698 return value.signum() == other.value.signum(); 699 700 //Ignore stored units; equality is based purely on magnitude in std units 701 return compareTo(other) == 0; 702 } 703 704 /** Returns a hash code value for this linear velocity. */ 705 public int hashCode() 706 { 707 if (isInfinite()) 708 return value.signum() > 0 ? "+infinity".hashCode() : "-infinity".hashCode(); 709 710 return Double.valueOf(toUnits(STD_UNITS).doubleValue()).hashCode(); 711 } 712 713 /** Compares this linear velocity with the {@code otherVel} for order. */ 714 public int compareTo(LinearVelocity otherVel) 715 { 716 //Treat two infinite values of same sign as equal, 717 //regardless of actual BigDecimal values 718 if (isInfinite() && otherVel.isInfinite()) 719 return value.signum() - otherVel.value.signum(); 720 721 //Avoid doing two unit conversions 722 return value.compareTo(otherVel.toUnits(units)); 723 } 724 725 //This is here for quick & dirty testing 726 /* 727 public static void main(String args[]) 728 { 729 LinearVelocity v1 = new LinearVelocity(3.0, LinearVelocityUnits.Z); 730 System.out.println("v1 = " + v1); 731 v1.convertTo(LinearVelocityUnits.KILOMETERS_PER_SECOND); 732 System.out.println("v1 = " + v1); 733 v1.convertTo(LinearVelocityUnits.Z); 734 System.out.println("v1 = " + v1); 735 736 System.out.println(); 737 738 LinearVelocity v2 = new LinearVelocity(10.0, LinearVelocityUnits.MILES_PER_HOUR); 739 System.out.println("v2 = " + v2); 740 v2.convertTo(LinearVelocityUnits.KILOMETERS_PER_SECOND); 741 System.out.println("v2 = " + v2); 742 v2.convertTo(LinearVelocityUnits.MILES_PER_HOUR); 743 System.out.println("v2 = " + v2); 744 745 System.out.println(); 746 747 LinearVelocity v3 = new LinearVelocity(10.0, LinearVelocityUnits.KILOMETERS_PER_SECOND); 748 System.out.println("v3 = " + v3); 749 v3.convertTo(LinearVelocityUnits.MILES_PER_HOUR); 750 System.out.println("v3 = " + v3); 751 v3.convertTo(LinearVelocityUnits.KILOMETERS_PER_SECOND); 752 System.out.println("v3 = " + v3); 753 754 System.out.println(); 755 756 LinearVelocity v4 = new LinearVelocity(300000.0, LinearVelocityUnits.KILOMETERS_PER_SECOND); 757 System.out.println("v4 = " + v4); 758 v4.convertTo(LinearVelocityUnits.Z); 759 System.out.println("v4 = " + v4); 760 v4.convertTo(LinearVelocityUnits.KILOMETERS_PER_SECOND); 761 System.out.println("v4 = " + v4); 762 } 763 */ 764 /* 765 public static void main(String... args) throws Exception 766 { 767 for (DistanceUnits du : DistanceUnits.values()) 768 for (TimeUnits tu : TimeUnits.values()) 769 { 770 LinearVelocityUnits vu = LinearVelocityUnits.from(du, tu); 771 System.out.println(" <xs:enumeration value=\""+vu.getSymbol()+"\"/>"); 772 } 773 } 774 */ 775 }