001 package edu.nrao.sss.astronomy; 002 003 import java.math.BigDecimal; 004 import java.util.Calendar; 005 import java.util.Date; 006 import java.util.Random; 007 008 import edu.nrao.sss.math.Polynomial; 009 import edu.nrao.sss.math.PolynomialTerm; 010 import edu.nrao.sss.measure.AngularVelocityUnits; 011 import edu.nrao.sss.measure.ArcUnits; 012 import edu.nrao.sss.measure.Distance; 013 import edu.nrao.sss.measure.DistanceUnits; 014 import edu.nrao.sss.measure.Latitude; 015 import edu.nrao.sss.measure.Longitude; 016 import edu.nrao.sss.measure.TimeInterval; 017 import edu.nrao.sss.util.EnumerationUtility; 018 019 /** 020 * Helper for test classes; builds sky positions with randomized data. 021 * <p> 022 * <b>Version Info:</b> 023 * <table style="margin-left:2em"> 024 * <tr><td>$Revision$</td></tr> 025 * <tr><td>$Date$</td></tr> 026 * <tr><td>$Author$</td></tr> 027 * </table></p> 028 * 029 * @author David M. Harland 030 * @since 2007-04-19 031 */ 032 public class SkyPositionBuilder 033 { 034 private static final EnumerationUtility ENUM_UTIL = 035 EnumerationUtility.getSharedInstance(); 036 037 private static final String INFO_ORIGIN = "SkyPositionBuilder.java"; 038 039 private Random random = new Random(System.currentTimeMillis()); 040 041 private EphemerisTableBuilder ephemBuilder = new EphemerisTableBuilder(); 042 043 //Used for coordinating multiple intervals 044 private Date timeIntervalEnd = null; 045 046 //============================================================================ 047 // 048 //============================================================================ 049 050 public SkyPosition makePosition() 051 { 052 SkyPosition position; 053 054 double posType = random.nextDouble(); 055 056 if (posType < 0.20) position = makeSimplePosition(); 057 else if (posType < 0.40) position = makePolynomialPosition(); 058 else if (posType < 0.60) position = makePolynomialTable(); 059 else if (posType < 0.80) position = makeEphemerisTable(); 060 else if (posType < 0.90) position = makeOrbit(); 061 else position = makeSolarSystemPosition(); 062 063 return position; 064 } 065 066 public SimpleSkyPosition makeSimplePosition() 067 { 068 SimpleSkyPosition position = new SimpleSkyPosition(); 069 070 position.setCoordinateSystem(ENUM_UTIL.getRandomValueFor(CelestialCoordinateSystem.class)); 071 position.setEpoch(random.nextDouble() < 0.2 ? Epoch.B1950 : Epoch.J2000); 072 position.setOriginOfInformation(INFO_ORIGIN); 073 074 Longitude longitude = makeLongitude(); 075 Latitude latitude = makeLatitude(); 076 Distance distance = makeBigDistance(); 077 078 position.getLongitude().set(longitude.getValue(), longitude.getUnits()); 079 position.getLatitude().set( latitude.getValue(), latitude.getUnits()); 080 position.getDistance().set( distance.getValue(), distance.getUnits()); 081 082 BigDecimal error = BigDecimal.valueOf(random.nextDouble() * 1e-4); 083 084 position.getLongitudeUncertainty().set(longitude.getValue().multiply(error), 085 longitude.getUnits()); 086 087 error = BigDecimal.valueOf(random.nextDouble() * 1e-4); 088 089 position.getLatitudeUncertainty().set(latitude.getValue().multiply(error), 090 latitude.getUnits()); 091 092 error = BigDecimal.valueOf(random.nextDouble() * 1e-4); 093 094 position.getDistanceUncertainty().set(error.multiply(distance.getValue()), 095 distance.getUnits()); 096 097 return position; 098 } 099 100 public EphemerisTable makeEphemerisTable() 101 { 102 return ephemBuilder.makeTable(); 103 } 104 105 public Orbit makeOrbit() 106 { 107 Orbit orbit = new Orbit(); 108 109 orbit.setOriginOfInformation(INFO_ORIGIN); 110 111 orbit.setArgumentOfPeriapsis(360.0 * random.nextDouble()); 112 orbit.setEccentricity(0.5 * random.nextDouble()); 113 orbit.setInclination(45.0 * random.nextDouble()); 114 orbit.setMeanAnomaly(360.0 * random.nextDouble()); 115 orbit.setRightAscensionAscendingNode( 116 new Longitude(Double.toString(360.0 * random.nextDouble()))); 117 orbit.setSemiMajorAxis(0.1 + 49.9 * random.nextDouble()); 118 119 return orbit; 120 } 121 122 public PolynomialPositionTable makePolynomialTable() 123 { 124 return makePolynomialTable(false); 125 } 126 127 public PolynomialPositionTable makePolynomialTable(boolean wellFormed) 128 { 129 PolynomialPositionTable table = new PolynomialPositionTable(); 130 131 int size = 3 + random.nextInt(17); 132 133 for (int p=0; p < size; p++) 134 { 135 table.add(makePolynomialPosition()); 136 137 if (!wellFormed) 138 timeIntervalEnd = null; 139 } 140 141 timeIntervalEnd = null; 142 143 return table; 144 } 145 146 public PolynomialPosition makePolynomialPosition() 147 { 148 return makePolynomialPosition(new PolynomialPosition()); 149 } 150 151 private PolynomialPosition makePolynomialPosition(PolynomialPosition pp) 152 { 153 pp.setValidTime(makeTimeInterval(timeIntervalEnd)); 154 pp.setReferenceTime(pp.getValidTime().getStart()); 155 pp.setEpoch(random.nextDouble() < 0.2 ? Epoch.B1950 : Epoch.J2000); 156 pp.setOriginOfInformation(INFO_ORIGIN); 157 pp.setLatitudeAtTimeZero(new Latitude(Double.toString(-90.0 + 180.0 * random.nextDouble()))); 158 pp.setLongitudeAtTimeZero(new Longitude(Double.toString(360.0 * random.nextDouble()))); 159 Polynomial eqn = new Polynomial(); 160 eqn.add(new PolynomialTerm(-100.0 + 200.0 * random.nextDouble(), 1)); 161 pp.setRadialMotion(eqn); 162 163 //0, 1, or 2 motion terms 164 double d0; 165 int count = random.nextInt(3); 166 if (count < 1.0) //very far away sources 167 { 168 d0 = 100.0 + 10000.0 * random.nextDouble(); 169 pp.setDistanceAtTimeZero(new Distance(BigDecimal.valueOf(d0), 170 DistanceUnits.LIGHT_YEAR)); 171 } 172 else if (count < 2.0) //far away sources 173 { 174 d0 = 5.0 + 100.0 * random.nextDouble(); 175 pp.setDistanceAtTimeZero(new Distance(BigDecimal.valueOf(d0), 176 DistanceUnits.LIGHT_YEAR)); 177 178 pp.setLatitudeVelocityUnits(AngularVelocityUnits.MILLI_ARC_SECONDS_PER_YEAR); 179 eqn = new Polynomial(); 180 eqn.add(new PolynomialTerm(-500.0 + 1000.0 * random.nextDouble(), 1)); 181 pp.setLatitudeMotion(eqn); 182 183 pp.setLongitudeVelocityUnits(AngularVelocityUnits.MILLI_ARC_SECONDS_PER_YEAR); 184 eqn = new Polynomial(); 185 eqn.add(new PolynomialTerm(-500.0 + 1000.0 * random.nextDouble(), 1)); 186 pp.setLongitudeMotion(eqn); 187 } 188 else //nearby sources 189 { 190 d0 = 3.0 + 97.0 * random.nextDouble(); 191 pp.setDistanceAtTimeZero(new Distance(BigDecimal.valueOf(d0), 192 DistanceUnits.ASTRONOMICAL_UNIT)); 193 194 pp.setLatitudeVelocityUnits(AngularVelocityUnits.ARC_SECONDS_PER_DAY); 195 eqn = new Polynomial(); 196 eqn.add(new PolynomialTerm(-50.0 + 100.0 * random.nextDouble(), 1)); 197 eqn.add(new PolynomialTerm(-5.0 + 10.0 * random.nextDouble(), 2)); 198 pp.setLatitudeMotion(eqn); 199 200 pp.setLongitudeVelocityUnits(AngularVelocityUnits.ARC_SECONDS_PER_DAY); 201 eqn = new Polynomial(); 202 eqn.add(new PolynomialTerm(-50.0 + 100.0 * random.nextDouble(), 1)); 203 eqn.add(new PolynomialTerm(-5.0 + 10.0 * random.nextDouble(), 2)); 204 pp.setLongitudeMotion(eqn); 205 } 206 207 return pp; 208 } 209 210 private static final String[] BODIES = 211 { 212 "Mercury", "Venus", "Mars", "Ceres", "Vesta", "Jupiter", "Saturn", 213 "Uranus", "Neptune", "Pluto", "Ida" 214 }; 215 216 public SolarSystemBodyPosition makeSolarSystemPosition() 217 { 218 SolarSystemBodyPosition position = 219 new SolarSystemBodyPosition(BODIES[random.nextInt(BODIES.length)]); 220 221 //TODO more random stuff 222 223 return position; 224 } 225 226 //============================================================================ 227 // HELPERS 228 //============================================================================ 229 230 private TimeInterval makeTimeInterval(Date startTime) 231 { 232 int year, month, day; 233 Date from; 234 Calendar cal = Calendar.getInstance(); 235 236 if (startTime == null) 237 { 238 year = 1950 + random.nextInt(55); 239 month = random.nextInt(12); 240 day = 1 + random.nextInt(27); 241 cal.set(year, month, day); 242 243 from = cal.getTime(); 244 } 245 else 246 { 247 cal.setTime(startTime); 248 249 from = startTime; 250 } 251 252 cal.add(Calendar.DATE, random.nextInt(3000)); 253 cal.add(Calendar.SECOND, random.nextInt(24*60*60)); 254 255 timeIntervalEnd = cal.getTime(); 256 257 return new TimeInterval(from, timeIntervalEnd); 258 } 259 260 private Longitude makeLongitude() 261 { 262 ArcUnits units = ENUM_UTIL.getRandomValueFor(ArcUnits.class); 263 264 BigDecimal value = units.toFullCircle().multiply(new BigDecimal(random.nextDouble())); 265 266 return new Longitude(value, units); 267 } 268 269 private Latitude makeLatitude() 270 { 271 ArcUnits units = ENUM_UTIL.getRandomValueFor(ArcUnits.class); 272 273 BigDecimal value = units.toQuarterCircle().multiply(new BigDecimal(random.nextDouble())); 274 275 if (random.nextDouble() < 0.5) 276 value = value.negate(); 277 278 return new Latitude(value, units); 279 } 280 281 private Distance makeBigDistance() 282 { 283 DistanceUnits units = null; 284 switch(random.nextInt(3)) 285 { 286 case 0: units = DistanceUnits.KILOMETER; break; 287 case 1: units = DistanceUnits.ASTRONOMICAL_UNIT; break; 288 case 2: units = DistanceUnits.LIGHT_YEAR; break; 289 } 290 291 BigDecimal au = BigDecimal.valueOf(random.nextInt(1000000) + 1); 292 BigDecimal value = DistanceUnits.ASTRONOMICAL_UNIT.toUnits(units).multiply(au); 293 294 return new Distance(value, units); 295 } 296 }