├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── contour
│ │ ├── algorithm
│ │ ├── IDW.java
│ │ ├── KDTree.java
│ │ └── Kriging.java
│ │ ├── bean
│ │ ├── DrawStyle.java
│ │ ├── Tuple2.java
│ │ ├── Tuple3.java
│ │ └── Tuple5.java
│ │ ├── draw
│ │ ├── Contour.java
│ │ └── spatial
│ │ │ ├── Border.java
│ │ │ ├── BorderLine.java
│ │ │ ├── BorderPoint.java
│ │ │ ├── EndPoint.java
│ │ │ ├── Extent.java
│ │ │ ├── IJPoint.java
│ │ │ ├── LPolygon.java
│ │ │ ├── LegendPara.java
│ │ │ ├── Line.java
│ │ │ ├── PointD.java
│ │ │ ├── PointF.java
│ │ │ ├── PolyLine.java
│ │ │ └── Polygon.java
│ │ └── utils
│ │ ├── CsvParser.java
│ │ ├── EncodeUtils.java
│ │ ├── MathsUtil.java
│ │ └── SphericalMercator.java
└── resources
│ └── log4j.properties
└── test
├── java
├── color
│ └── ColorTest.java
├── contour
│ ├── IDW
│ │ ├── IDWImage.java
│ │ ├── IDWTest.java
│ │ └── IDWutil.java
│ ├── common
│ │ └── AbstractImage.java
│ ├── kriging
│ │ ├── KrigingImage.java
│ │ └── KrigingTest.java
│ └── utils
│ │ ├── ColorUtils.java
│ │ ├── FileUtils.java
│ │ ├── InterpolateRgb.java
│ │ ├── MapUtils.java
│ │ └── PakoGzipUtils.java
└── graphics
│ └── GraphicsTest.java
└── resources
└── input
├── border.csv
└── data.csv
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 | *target
22 | *.vscode
23 | *.settings*
24 | .project
25 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
26 | hs_err_pid*
27 |
28 | !/lib/*.jar
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 David Xu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # jcontour
2 |
3 | jcontour is a Java-based project about plotting meteorological contours. It integrates inverse distance weighting (IDW) and ordinary kriging interpolation algorithms, providing tools for visualizing and analyzing meteorological data.
4 |
5 | ## Features
6 |
7 | - **Inverse Distance Weighting (IDW) Interpolation**: This algorithm estimates unknown data values based on known points, using inverse distance weighting.
8 | - **Ordinary Kriging Interpolation**: A geostatistical method that considers the spatial correlation between known points to estimate unknown data values. The kriging algorithm in this project references the open-source library [oeo4b/kriging](https://github.com/oeo4b/kriging).
9 | - **Geometric Drawing Calculations**: For contour plotting and related display calculations, I utilize code borrowed from [meteoinfo/wContour](https://github.com/meteoinfo/wContour), specifically dealing with KD-TREE and POLYGON functionalities.
10 |
11 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 | jcontour
7 | jcontour
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | 1.8
12 |
13 |
14 |
15 |
16 | org.slf4j
17 | slf4j-log4j12
18 | 1.7.25
19 |
20 |
21 | org.apache.commons
22 | commons-csv
23 | 1.0
24 |
25 |
26 | junit
27 | junit
28 | 4.12
29 | test
30 |
31 |
32 | com.alibaba
33 | fastjson
34 | 1.2.67
35 | test
36 |
37 |
38 |
39 |
40 | jcontour-1.0.0-SNAPSHOT
41 |
42 |
43 |
44 | org.apache.maven.plugins
45 | maven-compiler-plugin
46 | 3.1
47 |
48 | ${java.version}
49 | ${java.version}
50 | UTF-8
51 | true
52 |
53 |
54 |
55 |
56 |
57 | org.apache.maven.plugins
58 | maven-dependency-plugin
59 | 3.0.1
60 |
61 |
62 | copy-dependencies
63 | package
64 |
65 | copy-dependencies
66 |
67 |
68 | ${project.build.directory}/lib
69 | false
70 | false
71 | true
72 |
73 |
74 |
75 |
76 |
77 |
78 | org.apache.maven.plugins
79 | maven-surefire-plugin
80 | 2.5
81 |
82 | true
83 |
84 |
85 |
86 |
87 | org.apache.maven.plugins
88 | maven-jar-plugin
89 | 2.4
90 |
91 |
92 |
93 | false
94 |
95 |
96 |
97 | true
98 |
101 | lib/
102 |
103 |
104 |
105 |
106 |
107 | **/assembly/
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/src/main/java/contour/algorithm/IDW.java:
--------------------------------------------------------------------------------
1 | package contour.algorithm;
2 |
3 | import java.awt.geom.Point2D;
4 | import java.util.ArrayList;
5 | import java.util.Arrays;
6 | import java.util.Comparator;
7 | import java.util.List;
8 |
9 | import contour.algorithm.KDTree.Euclidean;
10 |
11 | /**
12 | * Interpolate class - including the functions of interpolation
13 | *
14 | * @author Yaqiang Wang
15 | * @version $Revision: 1.6 $
16 | */
17 | public class IDW {
18 | //
19 | /**
20 | * Create grid x/y coordinate arrays with x/y delt
21 | *
22 | * @param Xlb x of left-bottom
23 | * @param Ylb y of left-bottom
24 | * @param Xrt x of right-top
25 | * @param Yrt y of right-top
26 | * @param XDelt x delt
27 | * @param YDelt y delt
28 | * @return X/Y coordinate arrays
29 | */
30 | public static List createGridXY_Delt(double Xlb, double Ylb, double Xrt, double Yrt, double XDelt, double YDelt) {
31 | int i, Xnum, Ynum;
32 | Xnum = (int) ((Xrt - Xlb) / XDelt + 1);
33 | Ynum = (int) ((Yrt - Ylb) / YDelt + 1);
34 | double[] X = new double[Xnum];
35 | double[] Y = new double[Ynum];
36 | for (i = 0; i < Xnum; i++) {
37 | X[i] = Xlb + i * XDelt;
38 | }
39 | for (i = 0; i < Ynum; i++) {
40 | Y[i] = Ylb + i * YDelt;
41 | }
42 |
43 | List values = new ArrayList<>();
44 | values.add(X);
45 | values.add(Y);
46 | return values;
47 | }
48 |
49 | /**
50 | * Create grid X/Y coordinate
51 | *
52 | * @param Xlb X left bottom
53 | * @param Ylb Y left bottom
54 | * @param Xrt X right top
55 | * @param Yrt Y right top
56 | * @param X X coordinate
57 | * @param Y Y coordinate
58 | */
59 | public static void createGridXY_Num(double Xlb, double Ylb, double Xrt, double Yrt,
60 | double[] X, double[] Y) {
61 | int i;
62 | double XDelt, YDelt;
63 | int Xnum = X.length;
64 | int Ynum = Y.length;
65 | XDelt = (Xrt - Xlb) / Xnum;
66 | YDelt = (Yrt - Ylb) / Ynum;
67 | for (i = 0; i < Xnum; i++) {
68 | X[i] = Xlb + i * XDelt;
69 | }
70 | for (i = 0; i < Ynum; i++) {
71 | Y[i] = Ylb + i * YDelt;
72 | }
73 | System.out.println("像元XDelt"+XDelt);
74 | System.out.println("像元YDelt"+YDelt);
75 | }
76 |
77 | static List> searchPointsInRange(double[][] sCoords,
78 | double[] center,
79 | double longSemiAxisWidth,
80 | double shortSemiAxisWidth) {
81 | List
633 | //
634 | /**
635 | * Assign point value to grid value
636 | *
637 | * @param SCoords point value array
638 | * @param X x coordinate
639 | * @param Y y coordinate
640 | * @param unDefData undefine value
641 | * @return grid data
642 | */
643 | public static double[][] assignPointToGrid(double[][] SCoords, double[] X, double[] Y,
644 | double unDefData) {
645 | int rowNum, colNum, pNum;
646 | colNum = X.length;
647 | rowNum = Y.length;
648 | pNum = SCoords.length;
649 | double[][] GCoords = new double[rowNum][colNum];
650 | double dX = X[1] - X[0];
651 | double dY = Y[1] - Y[0];
652 | int[][] pNums = new int[rowNum][colNum];
653 |
654 | for (int i = 0; i < rowNum; i++) {
655 | for (int j = 0; j < colNum; j++) {
656 | pNums[i][j] = 0;
657 | GCoords[i][j] = 0.0;
658 | }
659 | }
660 |
661 | for (int p = 0; p < pNum; p++) {
662 | if (doubleEquals(SCoords[p][2], unDefData)) {
663 | continue;
664 | }
665 |
666 | double x = SCoords[p][0];
667 | double y = SCoords[p][1];
668 | if (x < X[0] || x > X[colNum - 1]) {
669 | continue;
670 | }
671 | if (y < Y[0] || y > Y[rowNum - 1]) {
672 | continue;
673 | }
674 |
675 | int j = (int) ((x - X[0]) / dX);
676 | int i = (int) ((y - Y[0]) / dY);
677 | pNums[i][j] += 1;
678 | GCoords[i][j] += SCoords[p][2];
679 | }
680 |
681 | for (int i = 0; i < rowNum; i++) {
682 | for (int j = 0; j < colNum; j++) {
683 | if (pNums[i][j] == 0) {
684 | GCoords[i][j] = unDefData;
685 | } else {
686 | GCoords[i][j] = GCoords[i][j] / pNums[i][j];
687 | }
688 | }
689 | }
690 |
691 | return GCoords;
692 | }
693 |
694 | private static boolean doubleEquals(double a, double b) {
695 | //if (Math.Abs(a - b) < 0.000001)
696 | if (Math.abs(a / b - 1) < 0.00000000001) {
697 | return true;
698 | } else {
699 | return false;
700 | }
701 | }
702 | //
703 | }
704 |
--------------------------------------------------------------------------------
/src/main/java/contour/algorithm/KDTree.java:
--------------------------------------------------------------------------------
1 | package contour.algorithm;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 |
6 | public abstract class KDTree {
7 |
8 | //use a big bucketSize so that we have less node bounds (for more cache hits) and better splits
9 | private static final int _bucketSize = 50;
10 |
11 | private final int _dimensions;
12 | private int _nodes;
13 | private final Node root;
14 | private final ArrayList nodeList = new ArrayList<>();
15 |
16 | //prevent GC from having to collect _bucketSize*dimensions*8 bytes each time a leaf splits
17 | private double[] mem_recycle;
18 |
19 | //the starting values for bounding boxes, for easy access
20 | private final double[] bounds_template;
21 |
22 | //one big self-expanding array to keep all the node bounding boxes so that they stay in cache
23 | // node bounds available at:
24 | //low: 2 * _dimensions * node.index + 2 * dim
25 | //high: 2 * _dimensions * node.index + 2 * dim + 1
26 | private final ContiguousDoubleArrayList nodeMinMaxBounds;
27 |
28 | private KDTree(int dimensions) {
29 | _dimensions = dimensions;
30 |
31 | //initialise this big so that it ends up in 'old' memory
32 | nodeMinMaxBounds = new ContiguousDoubleArrayList(512 * 1024 / 8 + 2 * _dimensions);
33 | mem_recycle = new double[_bucketSize * dimensions];
34 |
35 | bounds_template = new double[2 * _dimensions];
36 | Arrays.fill(bounds_template, Double.NEGATIVE_INFINITY);
37 | for (int i = 0, max = 2 * _dimensions; i < max; i += 2) {
38 | bounds_template[i] = Double.POSITIVE_INFINITY;
39 | }
40 |
41 | //and.... start!
42 | root = new Node();
43 | }
44 |
45 | public int nodes() {
46 | return _nodes;
47 | }
48 |
49 | public int size() {
50 | return root.entries;
51 | }
52 |
53 | public int addPoint(double[] location, T payload) {
54 |
55 | Node addNode = root;
56 | //Do a Depth First Search to find the Node where 'location' should be stored
57 | while (addNode.pointLocations == null) {
58 | addNode.expandBounds(location);
59 | if (location[addNode.splitDim] < addNode.splitVal) {
60 | addNode = nodeList.get(addNode.lessIndex);
61 | } else {
62 | addNode = nodeList.get(addNode.moreIndex);
63 | }
64 | }
65 | addNode.expandBounds(location);
66 |
67 | int nodeSize = addNode.add(location, payload);
68 |
69 | if (nodeSize % _bucketSize == 0) //try splitting again once every time the node passes a _bucketSize multiple
70 | //in case it is full of points of the same location and won't split
71 | {
72 | addNode.split();
73 | }
74 |
75 | return root.entries;
76 | }
77 |
78 | public ArrayList> nearestNeighbours(double[] searchLocation, int K) {
79 | IntStack stack = new IntStack();
80 | PrioQueue results = new PrioQueue<>(K, true);
81 |
82 | stack.push(root.index);
83 |
84 | int added = 0;
85 |
86 | while (stack.size() > 0) {
87 | int nodeIndex = stack.pop();
88 | if (added < K || results.peekPrio() > pointRectDist(nodeIndex, searchLocation)) {
89 | Node node = nodeList.get(nodeIndex);
90 | if (node.pointLocations == null) {
91 | node.search(searchLocation, stack);
92 | } else {
93 | added += node.search(searchLocation, results);
94 | }
95 | }
96 | }
97 |
98 | ArrayList> returnResults = new ArrayList<>(K);
99 | double[] priorities = results.priorities;
100 | Object[] elements = results.elements;
101 | for (int i = 0; i < K; i++) {//forward (closest first)
102 | SearchResult s = new SearchResult(priorities[i], (T) elements[i]);
103 | returnResults.add(s);
104 | }
105 | return returnResults;
106 | }
107 |
108 | public ArrayList ballSearch(double[] searchLocation, double radius) {
109 | IntStack stack = new IntStack();
110 | ArrayList results = new ArrayList<>();
111 |
112 | stack.push(root.index);
113 |
114 | while (stack.size() > 0) {
115 | int nodeIndex = stack.pop();
116 | if (radius > pointRectDist(nodeIndex, searchLocation)) {
117 | Node node = nodeList.get(nodeIndex);
118 | if (node.pointLocations == null) {
119 | stack.push(node.moreIndex).push(node.lessIndex);
120 | } else {
121 | node.searchBall(searchLocation, radius, results);
122 | }
123 | }
124 | }
125 | return results;
126 | }
127 |
128 | public ArrayList rectSearch(double[] mins, double[] maxs) {
129 | IntStack stack = new IntStack();
130 | ArrayList results = new ArrayList<>();
131 |
132 | stack.push(root.index);
133 |
134 | while (stack.size() > 0) {
135 | int nodeIndex = stack.pop();
136 | if (overlaps(mins, maxs, nodeIndex)) {
137 | Node node = nodeList.get(nodeIndex);
138 | if (node.pointLocations == null) {
139 | stack.push(node.moreIndex).push(node.lessIndex);
140 | } else {
141 | node.searchRect(mins, maxs, results);
142 | }
143 | }
144 | }
145 | return results;
146 |
147 | }
148 |
149 | abstract double pointRectDist(int offset, final double[] location);
150 |
151 | abstract double pointDist(double[] arr, double[] location, int index);
152 |
153 | boolean contains(double[] arr, double[] mins, double[] maxs, int index) {
154 |
155 | int offset = (index + 1) * mins.length;
156 |
157 | for (int i = mins.length; i-- > 0;) {
158 | double d = arr[--offset];
159 | if (mins[i] > d | d > maxs[i]) {
160 | return false;
161 | }
162 | }
163 | return true;
164 | }
165 |
166 | boolean overlaps(double[] mins, double[] maxs, int offset) {
167 | offset *= (2 * maxs.length);
168 | final double[] array = nodeMinMaxBounds.array;
169 | for (int i = 0; i < maxs.length; i++, offset += 2) {
170 | double bmin = array[offset], bmax = array[offset + 1];
171 | if (mins[i] > bmax | maxs[i] < bmin) {
172 | return false;
173 | }
174 | }
175 |
176 | return true;
177 | }
178 |
179 | public static class Euclidean extends KDTree {
180 |
181 | public Euclidean(int dims) {
182 | super(dims);
183 | }
184 |
185 | @Override
186 | double pointRectDist(int offset, final double[] location) {
187 | offset *= (2 * super._dimensions);
188 | double distance = 0;
189 | final double[] array = super.nodeMinMaxBounds.array;
190 | for (int i = 0; i < location.length; i++, offset += 2) {
191 |
192 | double diff = 0;
193 | double bv = array[offset];
194 | double lv = location[i];
195 | if (bv > lv) {
196 | diff = bv - lv;
197 | } else {
198 | bv = array[offset + 1];
199 | if (lv > bv) {
200 | diff = lv - bv;
201 | }
202 | }
203 | distance += sqr(diff);
204 | }
205 | return distance;
206 | }
207 |
208 | @Override
209 | double pointDist(double[] arr, double[] location, int index) {
210 | double distance = 0;
211 | int offset = (index + 1) * super._dimensions;
212 |
213 | for (int i = super._dimensions; i-- > 0;) {
214 | distance += sqr(arr[--offset] - location[i]);
215 | }
216 | return distance;
217 | }
218 |
219 | }
220 |
221 | public static class Manhattan extends KDTree {
222 |
223 | public Manhattan(int dims) {
224 | super(dims);
225 | }
226 |
227 | @Override
228 | double pointRectDist(int offset, final double[] location) {
229 | offset *= (2 * super._dimensions);
230 | double distance = 0;
231 | final double[] array = super.nodeMinMaxBounds.array;
232 | for (int i = 0; i < location.length; i++, offset += 2) {
233 |
234 | double diff = 0;
235 | double bv = array[offset];
236 | double lv = location[i];
237 | if (bv > lv) {
238 | diff = bv - lv;
239 | } else {
240 | bv = array[offset + 1];
241 | if (lv > bv) {
242 | diff = lv - bv;
243 | }
244 | }
245 | distance += (diff);
246 | }
247 | return distance;
248 | }
249 |
250 | @Override
251 | double pointDist(double[] arr, double[] location, int index) {
252 | double distance = 0;
253 | int offset = (index + 1) * super._dimensions;
254 |
255 | for (int i = super._dimensions; i-- > 0;) {
256 | distance += Math.abs(arr[--offset] - location[i]);
257 | }
258 | return distance;
259 | }
260 | }
261 |
262 | public static class WeightedManhattan extends KDTree {
263 |
264 | double[] weights;
265 |
266 | public WeightedManhattan(int dims) {
267 | super(dims);
268 | }
269 |
270 | public void setWeights(double[] newWeights) {
271 | weights = newWeights;
272 | }
273 |
274 | @Override
275 | double pointRectDist(int offset, final double[] location) {
276 | offset *= (2 * super._dimensions);
277 | double distance = 0;
278 | final double[] array = super.nodeMinMaxBounds.array;
279 | for (int i = 0; i < location.length; i++, offset += 2) {
280 |
281 | double diff = 0;
282 | double bv = array[offset];
283 | double lv = location[i];
284 | if (bv > lv) {
285 | diff = bv - lv;
286 | } else {
287 | bv = array[offset + 1];
288 | if (lv > bv) {
289 | diff = lv - bv;
290 | }
291 | }
292 | distance += (diff) * weights[i];
293 | }
294 | return distance;
295 | }
296 |
297 | @Override
298 | double pointDist(double[] arr, double[] location, int index) {
299 | double distance = 0;
300 | int offset = (index + 1) * super._dimensions;
301 |
302 | for (int i = super._dimensions; i-- > 0;) {
303 | distance += Math.abs(arr[--offset] - location[i]) * weights[i];
304 | }
305 | return distance;
306 | }
307 | }
308 |
309 | //NB! This Priority Queue keeps things with the LOWEST priority.
310 | //If you want highest priority items kept, negate your values
311 | private static class PrioQueue {
312 |
313 | Object[] elements;
314 | double[] priorities;
315 | private double minPrio;
316 | private int size;
317 |
318 | PrioQueue(int size, boolean prefill) {
319 | elements = new Object[size];
320 | priorities = new double[size];
321 | Arrays.fill(priorities, Double.POSITIVE_INFINITY);
322 | if (prefill) {
323 | minPrio = Double.POSITIVE_INFINITY;
324 | this.size = size;
325 | }
326 | }
327 | //uses O(log(n)) comparisons and one big shift of size O(N)
328 | //and is MUCH simpler than a heap --> faster on small sets, faster JIT
329 |
330 | void addNoGrow(S value, double priority) {
331 | int index = searchFor(priority);
332 | int nextIndex = index + 1;
333 | int length = size - index - 1;
334 | System.arraycopy(elements, index, elements, nextIndex, length);
335 | System.arraycopy(priorities, index, priorities, nextIndex, length);
336 | elements[index] = value;
337 | priorities[index] = priority;
338 |
339 | minPrio = priorities[size - 1];
340 | }
341 |
342 | int searchFor(double priority) {
343 | int i = size - 1;
344 | int j = 0;
345 | while (i >= j) {
346 | int index = (i + j) >>> 1;
347 | if (priorities[index] < priority) {
348 | j = index + 1;
349 | } else {
350 | i = index - 1;
351 | }
352 | }
353 | return j;
354 | }
355 |
356 | double peekPrio() {
357 | return minPrio;
358 | }
359 | }
360 |
361 | public static class SearchResult {
362 |
363 | public double distance;
364 | public S payload;
365 |
366 | SearchResult(double dist, S load) {
367 | distance = dist;
368 | payload = load;
369 | }
370 | }
371 |
372 | private class Node {
373 |
374 | //for accessing bounding box data
375 | // - if trees weren't so unbalanced might be better to use an implicit heap?
376 | int index;
377 |
378 | //keep track of size of subtree
379 | int entries;
380 |
381 | //leaf
382 | ContiguousDoubleArrayList pointLocations;
383 | ArrayList pointPayloads = new ArrayList<>(_bucketSize);
384 |
385 | //stem
386 | //Node less, more;
387 | int lessIndex, moreIndex;
388 | int splitDim;
389 | double splitVal;
390 |
391 | Node() {
392 | this(new double[_bucketSize * _dimensions]);
393 | }
394 |
395 | Node(double[] pointMemory) {
396 | pointLocations = new ContiguousDoubleArrayList(pointMemory);
397 | index = _nodes++;
398 | nodeList.add(this);
399 | nodeMinMaxBounds.add(bounds_template);
400 | }
401 |
402 | void search(double[] searchLocation, IntStack stack) {
403 | if (searchLocation[splitDim] < splitVal) {
404 | stack.push(moreIndex).push(lessIndex);//less will be popped first
405 | } else {
406 | stack.push(lessIndex).push(moreIndex);//more will be popped first
407 | }
408 | }
409 |
410 | //returns number of points added to results
411 | int search(double[] searchLocation, PrioQueue results) {
412 | int updated = 0;
413 | for (int j = entries; j-- > 0;) {
414 | double distance = pointDist(pointLocations.array, searchLocation, j);
415 | if (results.peekPrio() > distance) {
416 | updated++;
417 | results.addNoGrow(pointPayloads.get(j), distance);
418 | }
419 | }
420 | return updated;
421 | }
422 |
423 | void searchBall(double[] searchLocation, double radius, ArrayList results) {
424 |
425 | for (int j = entries; j-- > 0;) {
426 | double distance = pointDist(pointLocations.array, searchLocation, j);
427 | if (radius >= distance) {
428 | results.add(pointPayloads.get(j));
429 | }
430 | }
431 | }
432 |
433 | void searchRect(double[] mins, double[] maxs, ArrayList results) {
434 |
435 | for (int j = entries; j-- > 0;) {
436 | if (contains(pointLocations.array, mins, maxs, j)) {
437 | results.add(pointPayloads.get(j));
438 | }
439 | }
440 |
441 | }
442 |
443 | void expandBounds(double[] location) {
444 | entries++;
445 | int mio = index * 2 * _dimensions;
446 | for (int i = 0; i < _dimensions; i++) {
447 | nodeMinMaxBounds.array[mio] = Math.min(nodeMinMaxBounds.array[mio++], location[i]);
448 | nodeMinMaxBounds.array[mio] = Math.max(nodeMinMaxBounds.array[mio++], location[i]);
449 | }
450 | }
451 |
452 | int add(double[] location, T load) {
453 | pointLocations.add(location);
454 | pointPayloads.add(load);
455 | return entries;
456 | }
457 |
458 | void split() {
459 | int offset = index * 2 * _dimensions;
460 |
461 | double diff = 0;
462 | for (int i = 0; i < _dimensions; i++) {
463 | double min = nodeMinMaxBounds.array[offset];
464 | double max = nodeMinMaxBounds.array[offset + 1];
465 | if (max - min > diff) {
466 | double mean = 0;
467 | for (int j = 0; j < entries; j++) {
468 | mean += pointLocations.array[i + _dimensions * j];
469 | }
470 |
471 | mean = mean / entries;
472 | double varianceSum = 0;
473 |
474 | for (int j = 0; j < entries; j++) {
475 | varianceSum += sqr(mean - pointLocations.array[i + _dimensions * j]);
476 | }
477 |
478 | if (varianceSum > diff * entries) {
479 | diff = varianceSum / entries;
480 | splitVal = mean;
481 |
482 | splitDim = i;
483 | }
484 | }
485 | offset += 2;
486 | }
487 |
488 | //kill all the nasties
489 | if (splitVal == Double.POSITIVE_INFINITY) {
490 | splitVal = Double.MAX_VALUE;
491 | } else if (splitVal == Double.NEGATIVE_INFINITY) {
492 | splitVal = Double.MIN_VALUE;
493 | } else if (splitVal == nodeMinMaxBounds.array[index * 2 * _dimensions + 2 * splitDim + 1]) {
494 | splitVal = nodeMinMaxBounds.array[index * 2 * _dimensions + 2 * splitDim];
495 | }
496 |
497 | Node less = new Node(mem_recycle);//recycle that memory!
498 | Node more = new Node();
499 | lessIndex = less.index;
500 | moreIndex = more.index;
501 |
502 | //reduce garbage by factor of _bucketSize by recycling this array
503 | double[] pointLocation = new double[_dimensions];
504 | for (int i = 0; i < entries; i++) {
505 | System.arraycopy(pointLocations.array, i * _dimensions, pointLocation, 0, _dimensions);
506 | T load = pointPayloads.get(i);
507 |
508 | if (pointLocation[splitDim] < splitVal) {
509 | less.expandBounds(pointLocation);
510 | less.add(pointLocation, load);
511 | } else {
512 | more.expandBounds(pointLocation);
513 | more.add(pointLocation, load);
514 | }
515 | }
516 | if (less.entries * more.entries == 0) {
517 | //one of them was 0, so the split was worthless. throw it away.
518 | _nodes -= 2;//recall that bounds memory
519 | nodeList.remove(moreIndex);
520 | nodeList.remove(lessIndex);
521 | } else {
522 |
523 | //we won't be needing that now, so keep it for the next split to reduce garbage
524 | mem_recycle = pointLocations.array;
525 |
526 | pointLocations = null;
527 |
528 | pointPayloads.clear();
529 | pointPayloads = null;
530 | }
531 | }
532 |
533 | }
534 |
535 | private static class ContiguousDoubleArrayList {
536 |
537 | double[] array;
538 | int size;
539 |
540 | ContiguousDoubleArrayList() {
541 | this(300);
542 | }
543 |
544 | ContiguousDoubleArrayList(int size) {
545 | this(new double[size]);
546 | }
547 |
548 | ContiguousDoubleArrayList(double[] data) {
549 | array = data;
550 | }
551 |
552 | ContiguousDoubleArrayList add(double[] da) {
553 | if (size + da.length > array.length) {
554 | array = Arrays.copyOf(array, (array.length + da.length) * 2);
555 | }
556 |
557 | System.arraycopy(da, 0, array, size, da.length);
558 | size += da.length;
559 | return this;
560 | }
561 | }
562 |
563 | private static class IntStack {
564 |
565 | int[] array;
566 | int size;
567 |
568 | IntStack() {
569 | this(64);
570 | }
571 |
572 | IntStack(int size) {
573 | this(new int[size]);
574 | }
575 |
576 | IntStack(int[] data) {
577 | array = data;
578 | }
579 |
580 | IntStack push(int i) {
581 | if (size >= array.length) {
582 | array = Arrays.copyOf(array, (array.length + 1) * 2);
583 | }
584 |
585 | array[size++] = i;
586 | return this;
587 | }
588 |
589 | int pop() {
590 | return array[--size];
591 | }
592 |
593 | int size() {
594 | return size;
595 | }
596 | }
597 |
598 | static final double sqr(double d) {
599 | return d * d;
600 | }
601 | }
602 |
--------------------------------------------------------------------------------
/src/main/java/contour/algorithm/Kriging.java:
--------------------------------------------------------------------------------
1 | package contour.algorithm;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.Comparator;
6 | import java.util.List;
7 |
8 | import contour.utils.MathsUtil;
9 |
10 | /**
11 | * Kriging
12 | *
13 | * @author xuwei
14 | */
15 |
16 | public class Kriging {
17 | /**
18 | * 高斯模型
19 | */
20 | public final static String GAUSSIAN_MODEL = "gaussian";
21 | /**
22 | * 指数模型
23 | */
24 | public final static String EXPONENTIAL_MODEL = "exponential";
25 | /**
26 | * 球体模型
27 | */
28 | public final static String SPHERICAL_MODEL = "Spherical";
29 |
30 | public String model = EXPONENTIAL_MODEL;
31 | /**
32 | * 方差
33 | */
34 | public double sigma2 = 0;
35 | /**
36 | *
37 | */
38 | public double alpha = 100;
39 |
40 | private double[] targetValues;
41 |
42 | private double[] xList;
43 |
44 | private double[] yList;
45 |
46 | private double variogram_nugget = 0;
47 |
48 | private double variogram_range = 0;
49 |
50 | private double variogram_sill = 0;
51 |
52 | private double variogram_A = (double) 1 / 3;
53 |
54 | private int variogram_n = 0;
55 |
56 | private double[] variogram_K;
57 |
58 | private double[] variogram_M;
59 |
60 | public Kriging(double nugget, double range, double sill, double A, int n) {
61 | this.variogram_nugget = nugget;
62 | this.variogram_range = range;
63 | this.variogram_sill = sill;
64 | this.variogram_A = A;
65 | this.variogram_n = n;
66 | }
67 |
68 | public Kriging(String model, double sigma2, double alpha) {
69 | this.model = model;
70 | this.sigma2 = sigma2;
71 | this.alpha = alpha;
72 | }
73 |
74 | private double variogram_gaussian(double h) {
75 | double nugget = this.variogram_nugget;
76 | double sill = this.variogram_sill;
77 | double range = this.variogram_range;
78 | double A = this.variogram_A;
79 |
80 | return nugget + ((sill - nugget) / range) * (1.0 - Math.exp(-(1.0 / A) * Math.pow(h / range, 2)));
81 | }
82 |
83 | private double variogram_exponential(double h) {
84 | double nugget = this.variogram_nugget;
85 | double sill = this.variogram_sill;
86 | double range = this.variogram_range;
87 | double A = this.variogram_A;
88 |
89 | return nugget + ((sill - nugget) / range) * (1.0 - Math.exp(-(1.0 / A) * (h / range)));
90 | }
91 |
92 | private double variogram_spherical(double h) {
93 | double nugget = this.variogram_nugget;
94 | double sill = this.variogram_sill;
95 | double range = this.variogram_range;
96 |
97 | if (h > range)
98 | return nugget + (sill - nugget) / range;
99 |
100 | return nugget + ((sill - nugget) / range) * (1.5 * (h / range) - 0.5 * Math.pow(h / range, 3));
101 | }
102 |
103 | /**
104 | * training sample data
105 | *
106 | */
107 | public void train(double[] targetValues, double[] xList, double[] yList) {
108 | this.targetValues = targetValues;
109 | this.xList = xList;
110 | this.yList = yList;
111 |
112 | // lag distance/semivariance
113 | int size = this.targetValues.length;
114 | int distance_capacity = size * (size - 1) / 2;
115 | List distances = new ArrayList(distance_capacity);
116 | int i, j, k, l;
117 | for (i = 0, k = 0; i < size; i++) {
118 | for (j = 0; j < i; j++, k++) {
119 | double distance = Math.sqrt(Math.pow(xList[i] - xList[j], 2) + Math.pow(yList[i] - yList[j], 2));
120 | double detaValue = Math.abs(targetValues[i] - targetValues[j]);
121 | double[] arr = { distance, detaValue };
122 | distances.add(arr);
123 | }
124 | }
125 | Collections.sort(distances, new Comparator() {
126 | @Override
127 | public int compare(double[] o1, double[] o2) {
128 | double delta = o1[0] - o2[0];
129 | if (delta < 0) {
130 | return -1;
131 | } else if (delta > 0) {
132 | return 1;
133 | }
134 | return 0;
135 | }
136 | });
137 | this.variogram_range = distances.get(distance_capacity - 1)[0];
138 |
139 | // Bin lag distance
140 | int lags = distance_capacity > 30 ? 30 : distance_capacity;
141 | double tolerance = (double) this.variogram_range / lags;
142 | double[] lag = new double[lags];
143 | double[] semi = new double[lags];
144 | if (lags < 30) {
145 | for (l = 0; l < lags; l++) {
146 | double[] distance = distances.get(l);
147 | lag[l] = distance[0];
148 | semi[l] = distance[1];
149 | }
150 | } else {
151 | for (i = 0, j = 0, k = 0, l = 0; i < lags && j < distance_capacity; i++, k = 0) {
152 | while (distances.get(j)[0] <= ((i + 1) * tolerance)) {
153 | lag[l] += distances.get(j)[0];
154 | semi[l] += distances.get(j)[1];
155 | j++;
156 | k++;
157 | if (j >= distance_capacity)
158 | break;
159 | }
160 | if (k > 0) {
161 | lag[l] /= k;
162 | semi[l] /= k;
163 | l++;
164 | }
165 | }
166 | if (l < 2) {
167 | try {
168 | throw new Exception("Not enough points.");
169 | } catch (Exception e) {
170 | e.printStackTrace();
171 | }
172 | };
173 | }
174 |
175 | // Feature transformation
176 | size = l;
177 | this.variogram_range = lag[size - 1] - lag[0];
178 | double[] X = new double[size*2];
179 | for(int n=0;n xlim[1])
303 | xlim[1] = polygons[i][j][0];
304 | if (polygons[i][j][1] < ylim[0])
305 | ylim[0] = polygons[i][j][1];
306 | if (polygons[i][j][1] > ylim[1])
307 | ylim[1] = polygons[i][j][1];
308 | }
309 |
310 | // Alloc for O(n^2) space
311 | double xtarget, ytarget;
312 | int[] a = new int[2];
313 | int[] b = new int[2];
314 | double[] lxlim = new double[2]; // Local dimensions
315 | double[] lylim = new double[2]; // Local dimensions
316 | int x = (int)Math.ceil((xlim[1] - xlim[0]) / xWidth);
317 | int y = (int)Math.ceil((ylim[1] - ylim[0]) / yWidth);
318 |
319 | double[][] A = new double[x + 1][];
320 | for (i = 0; i <= x; i++) A[i] = new double[y + 1];
321 | for (i = 0; i < n; i++) {
322 | // Range for polygons[i]
323 | lxlim[0] = polygons[i][0][0];
324 | lxlim[1] = lxlim[0];
325 | lylim[0] = polygons[i][0][1];
326 | lylim[1] = lylim[0];
327 | for (j = 1; j < polygons[i].length; j++) { // Vertices
328 | if (polygons[i][j][0] < lxlim[0])
329 | lxlim[0] = polygons[i][j][0];
330 | if (polygons[i][j][0] > lxlim[1])
331 | lxlim[1] = polygons[i][j][0];
332 | if (polygons[i][j][1] < lylim[0])
333 | lylim[0] = polygons[i][j][1];
334 | if (polygons[i][j][1] > lylim[1])
335 | lylim[1] = polygons[i][j][1];
336 | }
337 |
338 | // Loop through polygon subspace
339 | a[0] = (int)Math.floor(((lxlim[0] - ((lxlim[0] - xlim[0]) % xWidth)) - xlim[0]) / xWidth);
340 | a[1] = (int)Math.ceil(((lxlim[1] - ((lxlim[1] - xlim[1]) % xWidth)) - xlim[0]) / xWidth);
341 | b[0] = (int)Math.floor(((lylim[0] - ((lylim[0] - ylim[0]) % yWidth)) - ylim[0]) / yWidth);
342 | b[1] = (int)Math.ceil(((lylim[1] - ((lylim[1] - ylim[1]) % yWidth)) - ylim[0]) / yWidth);
343 | for (j = a[0]; j <= a[1]; j++)
344 | for (k = b[0]; k <= b[1]; k++) {
345 | xtarget = xlim[0] + j * xWidth;
346 | ytarget = ylim[0] + k * yWidth;
347 | if (pip(polygons[i], xtarget, ytarget)) {
348 | A[j][k] = predict(xtarget, ytarget);
349 | }
350 | }
351 | }
352 |
353 | double maxValue = targetValues[0], minValue = targetValues[0];
354 | int len = targetValues.length;
355 | for(i=0; i < len; i++){
356 | if(targetValues[i] > maxValue) maxValue = targetValues[i];
357 | if(targetValues[i] < minValue) minValue = targetValues[i];
358 |
359 | }
360 |
361 | Grid grid = new Grid();
362 | grid.A = A;
363 | grid.xlim = xlim;
364 | grid.ylim = ylim;
365 | grid.zlim = new double[]{minValue, maxValue};
366 | grid.xWidth = xWidth;
367 | grid.yWidth = yWidth;
368 |
369 | return grid;
370 | }
371 |
372 | public double variance_gassian(double x, double y) {
373 | double[] k = new double[variogram_n];
374 | for (int i = 0; i < variogram_n; i++){
375 | k[i] = variogram_gaussian(Math.sqrt(Math.pow(x - this.xList[i], 2) +
376 | Math.pow(y - this.yList[i], 2)));
377 | }
378 |
379 | return variogram_gaussian(0) +
380 | MathsUtil.kriging_matrix_multiply(MathsUtil.kriging_matrix_multiply(k, variogram_K,
381 | 1, variogram_n, variogram_n),
382 | k, 1, variogram_n, 1)[0];
383 | }
384 |
385 | public double variance_exponential(double x, double y) {
386 | double[] k = new double[variogram_n];
387 | for (int i = 0; i < variogram_n; i++){
388 | k[i] = variogram_exponential(Math.sqrt(Math.pow(x - this.xList[i], 2) +
389 | Math.pow(y - this.yList[i], 2)));
390 | }
391 |
392 | return variogram_exponential(0) +
393 | MathsUtil.kriging_matrix_multiply(MathsUtil.kriging_matrix_multiply(k, variogram_K,
394 | 1, variogram_n, variogram_n),
395 | k, 1, variogram_n, 1)[0];
396 | }
397 |
398 | public double variance_spherical(double x, double y) {
399 | double[] k = new double[variogram_n];
400 | for (int i = 0; i < variogram_n; i++){
401 | k[i] = variogram_spherical(Math.sqrt(Math.pow(x - this.xList[i], 2) +
402 | Math.pow(y - this.yList[i], 2)));
403 | }
404 |
405 | return variogram_spherical(0) +
406 | MathsUtil.kriging_matrix_multiply(MathsUtil.kriging_matrix_multiply(k, variogram_K,
407 | 1, variogram_n, variogram_n),
408 | k, 1, variogram_n, 1)[0];
409 | }
410 |
411 | private double[] build_gassian_gram_matrix_with_prior(double[] xList, double[] yList){
412 | int n = xList.length;
413 | double[] K = new double[n * n];
414 | for(int i = 0; i < n; i++){
415 | for (int j = 0; j < i; j++) {
416 | K[i * n + j] = variogram_gaussian(Math.sqrt(Math.pow(xList[i] - xList[j], 2) +
417 | Math.pow(yList[i] - yList[j], 2)));
418 | K[j * n + i] = K[i * n + j];
419 | }
420 | K[i * n + i] = variogram_gaussian(0);
421 | }
422 | return K;
423 | }
424 |
425 | private double[] build_exponential_gram_matrix_with_prior(double[] xList, double[] yList){
426 | int n = xList.length;
427 | double[] K = new double[n * n];
428 | for(int i = 0; i < n; i++){
429 | for (int j = 0; j < i; j++) {
430 | K[i * n + j] = variogram_exponential(Math.sqrt(Math.pow(xList[i] - xList[j], 2) +
431 | Math.pow(yList[i] - yList[j], 2)));
432 | K[j * n + i] = K[i * n + j];
433 | }
434 | K[i * n + i] = variogram_exponential(0);
435 | }
436 | return K;
437 | }
438 |
439 | private double[] build_spherical_gram_matrix_with_prior(double[] xList, double[] yList){
440 | int n = xList.length;
441 | double[] K = new double[n * n];
442 | for(int i = 0; i < n; i++){
443 | for (int j = 0; j < i; j++) {
444 | K[i * n + j] = variogram_spherical(Math.sqrt(Math.pow(xList[i] - xList[j], 2) +
445 | Math.pow(yList[i] - yList[j], 2)));
446 | K[j * n + i] = K[i * n + j];
447 | }
448 | K[i * n + i] = variogram_spherical(0);
449 | }
450 | return K;
451 | }
452 |
453 | private boolean pip(double[][] polygons, double x, double y) {
454 | int i, j;
455 | boolean c = false;
456 | for (i = 0, j = polygons.length - 1; i < polygons.length; j = i++) {
457 | if (((polygons[i][1] > y) != (polygons[j][1] > y)) &&
458 | (x < (polygons[j][0] - polygons[i][0]) * (y - polygons[i][1]) / (polygons[j][1] - polygons[i][1]) + polygons[i][0])) {
459 | c = !c;
460 | }
461 | }
462 | return c;
463 | }
464 |
465 | }
--------------------------------------------------------------------------------
/src/main/java/contour/bean/DrawStyle.java:
--------------------------------------------------------------------------------
1 | package contour.bean;
2 |
3 | import java.awt.*;
4 |
5 | public class DrawStyle {
6 |
7 | public boolean show;
8 | public int size;
9 | public Color color;
10 |
11 | public DrawStyle(boolean show, int size, Color color) {
12 | this.show = show;
13 | this.size = size;
14 | this.color = color;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/contour/bean/Tuple2.java:
--------------------------------------------------------------------------------
1 | package contour.bean;
2 |
3 | public class Tuple2 {
4 |
5 | public final A _1;
6 | public final B _2;
7 |
8 | public Tuple2(A a, B b) {
9 | this._1 = a;
10 | this._2 = b;
11 | }
12 |
13 | @Override
14 | public String toString() {
15 | return "(" +
16 | _1 +
17 | ","+ _2 +
18 | ')';
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/contour/bean/Tuple3.java:
--------------------------------------------------------------------------------
1 | package contour.bean;
2 |
3 | public class Tuple3 {
4 |
5 | public final A _1;
6 | public final B _2;
7 | public final C _3;
8 |
9 | public Tuple3(A a, B b, C c) {
10 | this._1 = a;
11 | this._2 = b;
12 | this._3 = c;
13 | }
14 |
15 | @Override
16 | public String toString() {
17 | return "(" +
18 | _1 +
19 | ","+ _2 +
20 | ","+ _3 +
21 | ')';
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/contour/bean/Tuple5.java:
--------------------------------------------------------------------------------
1 | package contour.bean;
2 |
3 | /**
4 | * 颜色元组
5 | * Tuple5
6 | */
7 | public class Tuple5 {
8 | public final A _1;
9 | public final B _2;
10 | public final C _3;
11 | public final D _4;
12 | public final E _5;
13 |
14 | public Tuple5(A _1, B _2, C _3, D _4, E _5) {
15 | this._1 = _1;
16 | this._2 = _2;
17 | this._3 = _3;
18 | this._4 = _4;
19 | this._5 = _5;
20 | }
21 |
22 | @Override
23 | public String toString() {
24 | return "(" +
25 | _1 +
26 | "," + _2 +
27 | "," + _3 +
28 | "," + _4 +
29 | "," + _5 +
30 | ')';
31 | }
32 |
33 | }
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/Border.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | import java.util.List;
8 | import java.util.ArrayList;
9 |
10 | /**
11 | * Border class - contour line border
12 | *
13 | * @author Yaqiang Wang
14 | * @version $Revision: 1.6 $
15 | */
16 | public class Border {
17 | public List LineList = new ArrayList<>();
18 |
19 | /**
20 | * Constructor
21 | */
22 | public Border()
23 | {
24 |
25 | }
26 |
27 | /**
28 | * Get line number
29 | * @return Line number
30 | */
31 | public int getLineNum(){
32 | return LineList.size();
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/BorderLine.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * BorderLine class
12 | *
13 | * @author Yaqiang Wang
14 | */
15 | public class BorderLine {
16 |
17 | public double area;
18 | public Extent extent = new Extent();
19 | public boolean isOutLine;
20 | public boolean isClockwise;
21 | public List pointList = new ArrayList<>();
22 | public List ijPointList = new ArrayList<>();
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/BorderPoint.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | /**
8 | * BorderPoint class
9 | *
10 | * @author Yaqiang Wang
11 | */
12 | public class BorderPoint {
13 |
14 | public int Id;
15 | public int BorderIdx;
16 | public int BInnerIdx;
17 | public PointD Point = new PointD();
18 | public double Value;
19 |
20 | @Override
21 | public Object clone() {
22 | BorderPoint aBP = new BorderPoint();
23 | aBP.Id = Id;
24 | aBP.BorderIdx = BorderIdx;
25 | aBP.BInnerIdx = BInnerIdx;
26 | aBP.Point = Point;
27 | aBP.Value = Value;
28 |
29 | return aBP;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/EndPoint.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | /**
8 | * EndPoint class
9 | *
10 | * @author Yaqiang Wang
11 | */
12 | public class EndPoint {
13 |
14 | public PointD sPoint = new PointD();
15 | public PointD Point = new PointD();
16 | public int Index;
17 | public int BorderIdx;
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/Extent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | /**
8 | * Extent class
9 | *
10 | * @author Yaqiang Wang
11 | */
12 | public class Extent {
13 |
14 | public double xMin;
15 | public double yMin;
16 | public double xMax;
17 | public double yMax;
18 |
19 | /**
20 | * Constructor
21 | */
22 | public Extent() {
23 |
24 | }
25 |
26 | /**
27 | * Constructor
28 | *
29 | * @param minX Minimum x
30 | * @param maxX Maximum x
31 | * @param minY Minimum y
32 | * @param maxY Maximum y
33 | */
34 | public Extent(double minX, double maxX, double minY, double maxY) {
35 | xMin = minX;
36 | xMax = maxX;
37 | yMin = minY;
38 | yMax = maxY;
39 | }
40 |
41 | /**
42 | * Judge if this extent include another extent
43 | *
44 | * @param bExtent The extent
45 | * @return Is included or not
46 | */
47 | public boolean Include(Extent bExtent) {
48 | return xMin <= bExtent.xMin && xMax >= bExtent.xMax && yMin <= bExtent.yMin && yMax >= bExtent.yMax;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/IJPoint.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | /**
8 | * Point integer, to indicate the position in grid data
9 | *
10 | * @author Yaqiang Wang
11 | */
12 | public class IJPoint {
13 |
14 | public int I; // row in matrix
15 | public int J; // column in matrix
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/LPolygon.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | *
11 | * @author Yaqiang Wang
12 | */
13 | public class LPolygon {
14 |
15 | public double value;
16 | public boolean isFirst;
17 | public List pointList;
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/LegendPara.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | /**
8 | *
9 | * @author Yaqiang Wang
10 | */
11 | public class LegendPara {
12 |
13 | public boolean isVertical;
14 | public PointD startPoint;
15 | public double length;
16 | public double width;
17 | public double[] contourValues;
18 | public boolean isTriangle;
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/Line.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | /**
8 | *
9 | * Line class
10 | *
11 | * @author Yaqiang Wang
12 | */
13 | public class Line {
14 |
15 | public PointD P1;
16 | public PointD P2;
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/PointD.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | /**
8 | * PointD class
9 | *
10 | * @author Yaqiang Wang
11 | */
12 | public class PointD {
13 |
14 | public double X;
15 | public double Y;
16 |
17 | /**
18 | * Constructor
19 | */
20 | public PointD() {
21 | X = 0.0;
22 | Y = 0.0;
23 | }
24 |
25 | /**
26 | * Constructor
27 | *
28 | * @param x X
29 | * @param y Y
30 | */
31 | public PointD(double x, double y) {
32 | X = x;
33 | Y = y;
34 | }
35 |
36 | @Override
37 | public Object clone() {
38 | return new PointD(X, Y);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/PointF.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | /**
8 | * PointF class
9 | *
10 | * @author Yaqiang Wang
11 | */
12 | public class PointF {
13 |
14 | public float X;
15 | public float Y;
16 |
17 | /**
18 | * Constructor
19 | */
20 | public PointF() {
21 |
22 | }
23 |
24 | /**
25 | * Constructor
26 | *
27 | * @param x X
28 | * @param y Y
29 | */
30 | public PointF(float x, float y) {
31 | X = x;
32 | Y = y;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/PolyLine.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * PolyLine class
12 | *
13 | * @author Yaqiang Wang
14 | */
15 | public class PolyLine {
16 |
17 | public double Value;
18 | public String Type;
19 | public int BorderIdx;
20 | public List PointList = new ArrayList<>();
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/contour/draw/spatial/Polygon.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 Yaqiang Wang,
3 | * yaqiang.wang@gmail.com
4 | */
5 | package contour.draw.spatial;
6 |
7 | import java.util.ArrayList;
8 | import java.util.Collections;
9 | import java.util.List;
10 |
11 | import contour.draw.Contour;
12 |
13 | /**
14 | * Polygon class
15 | *
16 | * @author Yaqiang Wang
17 | */
18 | public class Polygon {
19 |
20 | //
21 | /**
22 | * If is border contour polygon
23 | */
24 | public boolean IsBorder;
25 | /**
26 | * If there is only inner border
27 | */
28 | public boolean IsInnerBorder = false;
29 | /**
30 | * Start value
31 | */
32 | public double LowValue;
33 | /**
34 | * End value
35 | */
36 | public double HighValue;
37 | /**
38 | * If clockwise
39 | */
40 | public boolean IsClockWise;
41 | /**
42 | * Start point index
43 | */
44 | public int StartPointIdx;
45 |
46 | /**
47 | * Is high center or not
48 | */
49 | public boolean IsHighCenter;
50 |
51 | /**
52 | * Extent - bordering rectangle
53 | */
54 | public Extent Extent = new Extent();
55 |
56 | /**
57 | * Area
58 | */
59 | public double Area;
60 |
61 | /**
62 | * Outline
63 | */
64 | public PolyLine OutLine = new PolyLine();
65 |
66 | /**
67 | * Hole lines
68 | */
69 | public List HoleLines = new ArrayList<>();
70 |
71 | /**
72 | * Hole index
73 | */
74 | public int HoleIndex;
75 |
76 | //
77 | //
78 | /**
79 | * Clone the object
80 | *
81 | * @return cloned Polygon object
82 | */
83 | public Object Clone() {
84 | Polygon aPolygon = new Polygon();
85 | aPolygon.IsBorder = IsBorder;
86 | aPolygon.LowValue = LowValue;
87 | aPolygon.HighValue = HighValue;
88 | aPolygon.IsClockWise = IsClockWise;
89 | aPolygon.StartPointIdx = StartPointIdx;
90 | aPolygon.IsHighCenter = IsHighCenter;
91 | aPolygon.Extent = Extent;
92 | aPolygon.Area = Area;
93 | aPolygon.OutLine = OutLine;
94 | aPolygon.HoleLines = new ArrayList<>(HoleLines);
95 | aPolygon.HoleIndex = HoleIndex;
96 |
97 | return aPolygon;
98 | }
99 |
100 | /**
101 | * Get if has holes
102 | *
103 | * @return Boolean
104 | */
105 | public boolean HasHoles() {
106 | return (HoleLines.size() > 0);
107 | }
108 |
109 | /**
110 | * Add a pohygon hole
111 | *
112 | * @param aPolygon The polygon hole
113 | */
114 | public void AddHole(Polygon aPolygon) {
115 | HoleLines.add(aPolygon.OutLine);
116 | }
117 |
118 | /**
119 | * Add a hole by point list
120 | *
121 | * @param pList The point list
122 | */
123 | public void AddHole(List pList) {
124 | if (Contour.isClockwise(pList)) {
125 | Collections.reverse(pList);
126 | }
127 |
128 | PolyLine aLine = new PolyLine();
129 | aLine.PointList = pList;
130 | HoleLines.add(aLine);
131 | }
132 | //
133 | }
134 |
--------------------------------------------------------------------------------
/src/main/java/contour/utils/CsvParser.java:
--------------------------------------------------------------------------------
1 | package contour.utils;
2 |
3 | import java.io.File;
4 | import java.nio.charset.Charset;
5 | import java.util.ArrayList;
6 | import java.util.HashMap;
7 | import java.util.Iterator;
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | import org.apache.commons.csv.CSVFormat;
12 | import org.apache.commons.csv.CSVParser;
13 | import org.apache.commons.csv.CSVRecord;
14 |
15 |
16 | public class CsvParser {
17 |
18 | public static List