View Javadoc
1   package au.gov.amsa.geo.model;
2   
3   import static au.gov.amsa.geo.model.Util.formatDate;
4   
5   import java.math.BigDecimal;
6   
7   import org.joda.time.DateTime;
8   
9   import com.google.common.base.Optional;
10  import com.google.common.base.Preconditions;
11  
12  public class Options {
13  
14  	private static final double KM_PER_NM = 1.852;
15  	private final BigDecimal originLat;
16  	private final BigDecimal originLon;
17  	private final BigDecimal cellSizeDegrees;
18  	private final double cellSizeDegreesDouble;
19  	private final Bounds bounds;
20  	private final Grid grid;
21  	private final Bounds filterBounds;
22  	private final SegmentOptions segmentOptions;
23  	private final Optional<Long> startTime;
24  	private final Optional<Long> finishTime;
25  
26  	public Options(BigDecimal originLat, BigDecimal originLon,
27  			BigDecimal cellSizeDegrees, Bounds bounds,
28  			Optional<Bounds> filterBounds, SegmentOptions segmentOptions,
29  			Optional<Long> startTime, Optional<Long> finishTime) {
30  		Preconditions.checkNotNull(originLat);
31  		Preconditions.checkNotNull(originLon);
32  		Preconditions.checkNotNull(cellSizeDegrees);
33  		Preconditions.checkArgument(cellSizeDegrees.doubleValue() > 0);
34  		Preconditions.checkNotNull(filterBounds);
35  		Preconditions.checkNotNull(startTime);
36  		Preconditions.checkNotNull(finishTime);
37  		this.originLat = originLat;
38  		this.originLon = originLon;
39  		this.cellSizeDegrees = cellSizeDegrees;
40  		this.bounds = bounds;
41  		if (filterBounds.isPresent())
42  			this.filterBounds = filterBounds.get();
43  		else
44  			this.filterBounds = bounds;
45  		this.segmentOptions = segmentOptions;
46  		this.startTime = startTime;
47  		this.finishTime = finishTime;
48  		grid = new Grid(this);
49  		this.cellSizeDegreesDouble = cellSizeDegrees.doubleValue();
50  	}
51  
52  	public int maxCells() {
53  		return (int) Math.round(bounds.getWidthDegrees()
54  				* bounds.getHeightDegrees() / cellSizeDegreesDouble
55  				/ cellSizeDegreesDouble);
56  	}
57  
58  	public static Bounds createFilterBounds(Bounds bounds,
59  			SegmentOptions segmentOptions) {
60  		double maxTimeTravellingHours = 4.0;
61  		double maxDistanceKm = maxTimeTravellingHours
62  				* segmentOptions.maxSpeedKnots() * KM_PER_NM;
63  		au.gov.amsa.util.navigation.Position topLeftBounds = au.gov.amsa.util.navigation.Position
64  				.create(bounds.getTopLeftLat(), bounds.getTopLeftLon());
65  		double topLat = topLeftBounds.predict(maxDistanceKm, 0).getLat();
66  		double leftLon = topLeftBounds.predict(maxDistanceKm, -90).getLon();
67  		au.gov.amsa.util.navigation.Position bottomRightBounds = au.gov.amsa.util.navigation.Position
68  				.create(bounds.getBottomRightLat(), bounds.getBottomRightLon());
69  
70  		double bottomLat = bottomRightBounds.predict(maxDistanceKm, 180)
71  				.getLat();
72  		double rightLon = bottomRightBounds.predict(maxDistanceKm, 90).getLon();
73  
74  		return new Bounds(topLat, leftLon, bottomLat, rightLon);
75  	}
76  
77  	public Optional<Long> getStartTime() {
78  		return startTime;
79  	}
80  
81  	public Optional<Long> getFinishTime() {
82  		return finishTime;
83  	}
84  
85  	public BigDecimal getOriginLat() {
86  		return originLat;
87  	}
88  
89  	public BigDecimal getOriginLon() {
90  		return originLon;
91  	}
92  
93  	public BigDecimal getCellSizeDegrees() {
94  		return cellSizeDegrees;
95  	}
96  
97  	public double getCellSizeDegreesAsDouble() {
98  		return cellSizeDegreesDouble;
99  	}
100 
101 	public Bounds getBounds() {
102 		return bounds;
103 	}
104 
105 	public Bounds getFilterBounds() {
106 		return filterBounds;
107 	}
108 
109 	public Grid getGrid() {
110 		return grid;
111 	}
112 
113 	@Override
114 	public String toString() {
115 		StringBuilder builder = new StringBuilder();
116 		builder.append("Options [originLat=");
117 		builder.append(originLat);
118 		builder.append(", originLon=");
119 		builder.append(originLon);
120 		builder.append(", cellSizeDegrees=");
121 		builder.append(cellSizeDegrees);
122 		builder.append(", bounds=");
123 		builder.append(bounds);
124 		builder.append(", filterBounds=");
125 		builder.append(filterBounds);
126 		builder.append(", startTime=");
127 		builder.append(formatDate(startTime));
128 		builder.append(", finishTime=");
129 		builder.append(formatDate(finishTime));
130 		builder.append(", segmentOptions=");
131 		builder.append(segmentOptions);
132 		builder.append("]");
133 		return builder.toString();
134 	}
135 
136 	public static Builder builder() {
137 		return new Builder();
138 	}
139 
140 	public static Builder builder(Options o) {
141 		return builder().bounds(o.getBounds())
142 				.cellSizeDegrees(o.getCellSizeDegrees())
143 				.filterBounds(o.getFilterBounds())
144 				.finishTime(o.getFinishTime()).startTime(o.getStartTime())
145 				.originLat(o.getOriginLat()).originLon(o.getOriginLon())
146 				.segmentOptions(o.getSegmentOptions());
147 	}
148 
149 	public SegmentOptions getSegmentOptions() {
150 		return segmentOptions;
151 	}
152 
153 	public static class Builder {
154 
155 		private BigDecimal originLat = BigDecimal.ZERO;
156 		private BigDecimal originLon = BigDecimal.ZERO;
157 		private BigDecimal cellSizeDegrees = BigDecimal.ONE;
158 		private Bounds bounds = new Bounds(15, 67, -60, 179);
159 		private SegmentOptions segmentOptions = SegmentOptions.builder()
160 				.build();
161 		private Optional<Bounds> filterBounds = Optional.absent();
162 		private Optional<Long> startTime = Optional.absent();
163 		private Optional<Long> finishTime = Optional.absent();
164 
165 		private Builder() {
166 		}
167 
168 		public Builder originLat(BigDecimal originLat) {
169 			this.originLat = originLat;
170 			return this;
171 		}
172 
173 		public Builder originLat(double originLat) {
174 			this.originLat = BigDecimal.valueOf(originLat);
175 			return this;
176 		}
177 
178 		public Builder originLon(BigDecimal originLon) {
179 			this.originLon = originLon;
180 			return this;
181 		}
182 
183 		public Builder originLon(double originLon) {
184 			this.originLon = BigDecimal.valueOf(originLon);
185 			return this;
186 		}
187 
188 		public Builder cellSizeDegrees(BigDecimal cellSizeDegrees) {
189 			this.cellSizeDegrees = cellSizeDegrees;
190 			return this;
191 		}
192 
193 		public Builder cellSizeDegrees(double cellSizeDegrees) {
194 			this.cellSizeDegrees = BigDecimal.valueOf(cellSizeDegrees)
195 					.setScale(30);
196 			return this;
197 		}
198 
199 		public Builder bounds(Bounds bounds) {
200 			this.bounds = bounds;
201 			return this;
202 		}
203 
204 		public Builder filterBounds(Bounds bounds) {
205 			this.filterBounds = Optional.of(bounds);
206 			return this;
207 		}
208 
209 		public Builder startTime(Optional<Long> startTime) {
210 			this.startTime = startTime;
211 			return this;
212 		}
213 
214 		public Builder startTime(String isoDateTimeFormat) {
215 			this.startTime = Optional.of(DateTime.parse(isoDateTimeFormat)
216 					.getMillis());
217 			return this;
218 		}
219 
220 		public Builder finishTime(Optional<Long> finishTime) {
221 			this.finishTime = finishTime;
222 			return this;
223 		}
224 
225 		public Builder finishTime(String isoDateTimeFormat) {
226 			this.finishTime = Optional.of(DateTime.parse(isoDateTimeFormat)
227 					.getMillis());
228 			return this;
229 		}
230 
231 		public Builder segmentOptions(SegmentOptions o) {
232 			this.segmentOptions = o;
233 			return this;
234 		}
235 
236 		public Options build() {
237 			return new Options(originLat, originLon, cellSizeDegrees, bounds,
238 					filterBounds, segmentOptions, startTime, finishTime);
239 		}
240 	}
241 
242 	public Builder buildFrom() {
243 		return builder(this);
244 	}
245 
246 }