1 | /*
|
---|
2 | * Class DigiGraph
|
---|
3 | *
|
---|
4 | * Class to digitize a graph presented as a gif, jpg or png
|
---|
5 | *
|
---|
6 | * WRITTEN BY: Dr Michael Thomas Flanagan
|
---|
7 | *
|
---|
8 | * DATE: September 2006
|
---|
9 | * UPDATE: 8 October 2006, 2 November 2006, 12 May 2008, 5 July 2008, 3 December 2008
|
---|
10 | *
|
---|
11 | * DOCUMENTATION:
|
---|
12 | * See Michael T Flanagan's Java library on-line web pages:
|
---|
13 | * http://www.ee.ucl.ac.uk/~mflanaga/java/
|
---|
14 | * http://www.ee.ucl.ac.uk/~mflanaga/java/DigiGraph.html
|
---|
15 | *
|
---|
16 | * Copyright (c) 2006 - 2008
|
---|
17 | *
|
---|
18 | * PERMISSION TO COPY:
|
---|
19 | *
|
---|
20 | * Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee,
|
---|
21 | * provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies
|
---|
22 | * and associated documentation or publications.
|
---|
23 | *
|
---|
24 | * Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice,
|
---|
25 | * this list of conditions and the following disclaimer and requires written permission from the Michael Thomas Flanagan:
|
---|
26 | *
|
---|
27 | * Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and
|
---|
28 | * the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission
|
---|
29 | * from the Michael Thomas Flanagan:
|
---|
30 | *
|
---|
31 | * Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose.
|
---|
32 | * Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software
|
---|
33 | * or its derivatives.
|
---|
34 | *
|
---|
35 | *****************************************************************************************************************************************************/
|
---|
36 |
|
---|
37 | package agents.anac.y2015.agentBuyogV2.flanagan.io;
|
---|
38 |
|
---|
39 | import java.awt.*;
|
---|
40 | import java.awt.image.*;
|
---|
41 | import java.awt.event.*;
|
---|
42 | import java.util.ArrayList;
|
---|
43 | import java.io.*;
|
---|
44 | import java.net.*;
|
---|
45 | import javax.swing.*;
|
---|
46 | import javax.swing.JFrame;
|
---|
47 |
|
---|
48 | import agents.anac.y2015.agentBuyogV2.flanagan.interpolation.CubicSpline;
|
---|
49 | import agents.anac.y2015.agentBuyogV2.flanagan.io.*;
|
---|
50 | import agents.anac.y2015.agentBuyogV2.flanagan.math.Fmath;
|
---|
51 | import agents.anac.y2015.agentBuyogV2.flanagan.plot.PlotGraph;
|
---|
52 |
|
---|
53 | public class DigiGraph extends Canvas implements MouseListener{
|
---|
54 |
|
---|
55 | private Image pic = null; // image containing graph to be digitised
|
---|
56 | private String imagePath = null; // path, i.e. address\name, of the .png, .gif or .jpg containing graph
|
---|
57 | private String imageName = null; // name of the .gif, .png or .jpg file containing graph
|
---|
58 | private String extension = null; // extension of file name, e.g. gif, png or jpg
|
---|
59 |
|
---|
60 | private String outputFile = null; // output file (containing digitisation values) name
|
---|
61 | private FileOutput fout = null; // output file (containing digitisation values) reference
|
---|
62 | private int trunc = 16; // number of decimal places in output data
|
---|
63 |
|
---|
64 | private String path = "C:"; // path for file selection window
|
---|
65 | private int windowWidth = 0; // width of the window for the graph in pixels
|
---|
66 | private int windowHeight = 0; // height of the window for the graph in pixels
|
---|
67 | private int closeChoice = 1; // =1 clicking on close icon causes window to close
|
---|
68 | // and the the program is exited.
|
---|
69 | // =2 clicking on close icon causes window to close
|
---|
70 | // leaving the program running.
|
---|
71 |
|
---|
72 | private int xPos = 0; // mouse x-axis position (in pixels)on last click
|
---|
73 | private int yPos = 0; // mouse y-axis position (in pixels)on last click
|
---|
74 | private int button = 0; // mouse button last clicked
|
---|
75 | // = 0; no button clicked
|
---|
76 | // = 1; left mouse button last clicked
|
---|
77 | // (= 2; middle mouse button last clicked)
|
---|
78 | // = 3; right mouse button last clicked
|
---|
79 | private int sumX = 0; // sum of xPos in calculation of a calibration point
|
---|
80 | private int sumY = 0; // sum of yPos in calculation of a calibration point
|
---|
81 | private int iSum = 0; // number of xPos and yPos in calculation of a calibration point
|
---|
82 | private boolean mouseEntered = false; // = true when mouse enters object
|
---|
83 | // = false when mouse leaves object
|
---|
84 | private double lowYvalue = 0.0; // Y-axis value (entered as double) of the clicked low Y-axis value
|
---|
85 | private double lowYaxisXpixel = 0.0; // X-axis pixel number of the clicked known low Y-axis value
|
---|
86 | private double lowYaxisYpixel = 0.0; // Y-axis pixel number of the clicked known low Y-axis value
|
---|
87 | private double highYvalue = 0.0; // Y-axis value (entered as double) of the clicked high Y-axis value
|
---|
88 | private double highYaxisXpixel = 0.0; // X-axis pixel number of the clicked known high Y-axis value
|
---|
89 | private double highYaxisYpixel = 0.0; // Y-axis pixel number of the clicked known high Y-axis value
|
---|
90 | private double lowXvalue = 0.0; // X-axis value (entered as double) of the clicked low X-axis value
|
---|
91 | private double lowXaxisXpixel = 0.0; // X-axis pixel number of the clicked known low X-axis value
|
---|
92 | private double lowXaxisYpixel = 0.0; // Y-axis pixel number of the clicked known low X-axis value
|
---|
93 | private double highXvalue = 0.0; // X-axis value (entered as double) of the clicked high X-axis value
|
---|
94 | private double highXaxisXpixel = 0.0; // X-axis pixel number of the clicked known high X-axis value
|
---|
95 | private double highXaxisYpixel = 0.0; // Y-axis pixel number of the clicked known high X-axis value
|
---|
96 |
|
---|
97 | private ArrayList<Integer> xAndYvalues = new ArrayList<Integer>();
|
---|
98 | // ArrayList holding clicked point xPos and yPos values
|
---|
99 | private int iCounter = 0; // counter for clicks or sum of clicks on first for calibration points
|
---|
100 | private double angleXaxis = 0.0; // clockwise angle from normal of x-axis (degrees)
|
---|
101 | private double angleYaxis = 0.0; // clockwise angle from normal of y-axis (degrees)
|
---|
102 | private double angleMean = 0.0; // mean clockwise angle of axes from normal (degrees)
|
---|
103 | private double angleTolerance = 0.0; // tolerance in above angle before a rotation of all points performed
|
---|
104 | // default option is to rotate if angle is not zero
|
---|
105 | private boolean rotationDone = false; // = false: no rotation of points performed
|
---|
106 | // = true: all points have been rotated
|
---|
107 |
|
---|
108 | private double[] xPosPixel = null; // x pixel values converted to double
|
---|
109 | private double[] yPosPixel = null; // y pixel values converted to double
|
---|
110 | private double[] xPositions = null; // Digitized and scaled x values
|
---|
111 | private double[] yPositions = null; // Digitized and scaled y values
|
---|
112 | private int nData = 0; // Number of points digitized (excluding calibration points)
|
---|
113 |
|
---|
114 | private int nInterpPoints = 0; // Nnumber of interpolation points
|
---|
115 | private boolean interpOpt = false; // = true if interpolation requested
|
---|
116 | private double[] xInterp = null; // Interpolated x values
|
---|
117 | private double[] yInterp = null; // Interpolated y values
|
---|
118 | private boolean plotOpt = true; // = false if plot of interpolated data not required
|
---|
119 |
|
---|
120 | private boolean noIdentical = true; // = true - all identical points stripped to one instance of the identical points
|
---|
121 | // = false - all identical points retained
|
---|
122 |
|
---|
123 | private int imageFormat = 0; // = 0 no image file loaded
|
---|
124 | // = 1 GIF format
|
---|
125 | // = 2 JPEG format
|
---|
126 | // = 3 PNG format
|
---|
127 |
|
---|
128 | private boolean digitizationDone = false; // = true when digitization complete
|
---|
129 |
|
---|
130 | private boolean noYlow = true; // = false when lower y-axis calibration point has been entered
|
---|
131 | private boolean noXlow = true; // = false when lower x-axis calibration point has been entered
|
---|
132 | private boolean noYhigh = true; // = false when higher y-axis calibration point has been entered
|
---|
133 | private boolean noXhigh = true; // = false when higher x-axis calibration point has been entered
|
---|
134 |
|
---|
135 | private boolean resize = false; // = true if image is resized
|
---|
136 |
|
---|
137 | // Create the window object
|
---|
138 | private JFrame window = new JFrame("Michael T Flanagan's digitizing program - DigiGraph");
|
---|
139 |
|
---|
140 | // Constructors
|
---|
141 | // image to be selected from a file select window
|
---|
142 | // window opens on default setting
|
---|
143 | public DigiGraph(){
|
---|
144 | super();
|
---|
145 |
|
---|
146 | // Set graph digitizing window size
|
---|
147 | setWindowSize();
|
---|
148 |
|
---|
149 | // select image
|
---|
150 | selectImage();
|
---|
151 |
|
---|
152 | // set image
|
---|
153 | setImage();
|
---|
154 |
|
---|
155 | // Name outputfile
|
---|
156 | outputFileChoice();
|
---|
157 |
|
---|
158 | // Add the MouseListener
|
---|
159 | addMouseListener(this);
|
---|
160 | }
|
---|
161 |
|
---|
162 | // image to be selected from a file select window
|
---|
163 | // window opens on path (windowPath) provided
|
---|
164 | public DigiGraph(String windowPath){
|
---|
165 | super();
|
---|
166 |
|
---|
167 | // Set graph digitizing window size
|
---|
168 | setWindowSize();
|
---|
169 |
|
---|
170 | // Set window path
|
---|
171 | this.path = windowPath;
|
---|
172 |
|
---|
173 | // select image
|
---|
174 | selectImage();
|
---|
175 |
|
---|
176 | // set image
|
---|
177 | setImage();
|
---|
178 |
|
---|
179 | // Name outputfile
|
---|
180 | outputFileChoice();
|
---|
181 |
|
---|
182 | // Add the MouseListener
|
---|
183 | addMouseListener(this);
|
---|
184 | }
|
---|
185 |
|
---|
186 | // Set graph digitizing window size
|
---|
187 | private void setWindowSize(){
|
---|
188 |
|
---|
189 | Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); // get computer screen size
|
---|
190 | this.windowWidth = screenSize.width - 30; // width of the window for the graph in pixels
|
---|
191 | this.windowHeight = screenSize.height - 40; // height of the window for the graph in pixels
|
---|
192 | }
|
---|
193 |
|
---|
194 | // Select graph image
|
---|
195 | private void selectImage(){
|
---|
196 |
|
---|
197 | // Identify computer
|
---|
198 | String computerName = null;
|
---|
199 | try{
|
---|
200 | InetAddress localaddress = InetAddress.getLocalHost();
|
---|
201 | computerName = localaddress.getHostName();
|
---|
202 | }
|
---|
203 | catch(UnknownHostException e){
|
---|
204 | System.err.println("Cannot detect local host : " + e);
|
---|
205 | }
|
---|
206 |
|
---|
207 | // Set path to file selection window
|
---|
208 | // Replace "name" by your "computer's name" and C:\\DigiGraphDirectory by the path to the directory containing the image to be digitized
|
---|
209 | // Default path is to the C:\ directory or system default directory if no C drive present
|
---|
210 | if(computerName.equals("name"))this.path = "C:\\DigiGraphDirectory";
|
---|
211 |
|
---|
212 | // select image file
|
---|
213 | FileChooser fc = new FileChooser(this.path);
|
---|
214 | this.imageName = fc.selectFile();
|
---|
215 | if(!fc.fileFound()){
|
---|
216 | System.out.println("Class DigiGraph: No successful selection of an image file occurred");
|
---|
217 | System.exit(0);
|
---|
218 | }
|
---|
219 | this.imagePath = fc.getPathName();
|
---|
220 |
|
---|
221 | int lastDot = this.imagePath.lastIndexOf('.');
|
---|
222 | this.extension = this.imagePath.substring(lastDot+1);
|
---|
223 | if(this.extension.equalsIgnoreCase("gif"))imageFormat=1;
|
---|
224 | if(this.extension.equalsIgnoreCase("jpg"))imageFormat=2;
|
---|
225 | if(this.extension.equalsIgnoreCase("jpeg"))imageFormat=2;
|
---|
226 | if(this.extension.equalsIgnoreCase("jpe"))imageFormat=2;
|
---|
227 | if(this.extension.equalsIgnoreCase("jfif"))imageFormat=2;
|
---|
228 | if(this.extension.equalsIgnoreCase("png"))imageFormat=3;
|
---|
229 | }
|
---|
230 |
|
---|
231 | // Set graph image
|
---|
232 | private void setImage(){
|
---|
233 | this.pic = Toolkit.getDefaultToolkit().getImage(this.imagePath);
|
---|
234 | }
|
---|
235 |
|
---|
236 | // Name outputfile and set number of decimal placess in the output data
|
---|
237 | private void outputFileChoice(){
|
---|
238 | int posdot = this.imagePath.lastIndexOf('.');
|
---|
239 | this.outputFile = this.imagePath.substring(0, posdot) + "_digitized.txt";
|
---|
240 | this.outputFile = Db.readLine("Enter output file name ", this.outputFile);
|
---|
241 | this.fout = new FileOutput(this.outputFile);
|
---|
242 | this.trunc = Db.readInt("Enter number of decimal places required in output data ", this.trunc);
|
---|
243 | }
|
---|
244 |
|
---|
245 | // Reset the number of decimal places in the output data
|
---|
246 | public void setTruncation(int trunc){
|
---|
247 | this.trunc = trunc;
|
---|
248 | }
|
---|
249 |
|
---|
250 | // Reset tolerance in axis rotation before applying rotation (degrees)
|
---|
251 | public void setRotationTolerance(double tol){
|
---|
252 | this.angleTolerance = tol;
|
---|
253 | }
|
---|
254 |
|
---|
255 | // Reset option of plotting the data
|
---|
256 | // Prevents a plot of the digitized data and the interpolated data, if interpolation optiion chosen,
|
---|
257 | // from being displayed
|
---|
258 | public void noPlot(){
|
---|
259 | this.plotOpt = false;;
|
---|
260 | }
|
---|
261 |
|
---|
262 | // Reset path for selection window
|
---|
263 | public void setPath(String path){
|
---|
264 | this.path = path;
|
---|
265 | }
|
---|
266 |
|
---|
267 | // Reset height of graph window (pixels)
|
---|
268 | public void setWindowHeight(int windowHeight){
|
---|
269 | this.windowHeight = windowHeight;
|
---|
270 | }
|
---|
271 |
|
---|
272 | // Reset width of graph window (pixels)
|
---|
273 | public void setWindowWidth(int windowWidth){
|
---|
274 | this.windowWidth = windowWidth;
|
---|
275 | }
|
---|
276 |
|
---|
277 | // Reset close choice
|
---|
278 | public void setCloseChoice(int choice){
|
---|
279 | this.closeChoice = choice;
|
---|
280 | }
|
---|
281 |
|
---|
282 | // Reset stripping of identical points option
|
---|
283 | // Keep all identical points
|
---|
284 | public void keepIdenticalPoints(){
|
---|
285 | this.noIdentical = false;
|
---|
286 | }
|
---|
287 |
|
---|
288 | // The paint method to display the graph.
|
---|
289 | public void paint(Graphics g){
|
---|
290 |
|
---|
291 | // Call graphing method
|
---|
292 | graph(g);
|
---|
293 | }
|
---|
294 |
|
---|
295 | // Set up the window, show graph and digitize
|
---|
296 | public void digitize(){
|
---|
297 |
|
---|
298 | // Set the initial size of the graph window
|
---|
299 | this.window.setSize(this.windowWidth, this.windowHeight);
|
---|
300 |
|
---|
301 | // Set background colour
|
---|
302 | this.window.getContentPane().setBackground(Color.white);
|
---|
303 |
|
---|
304 | // Choose close box
|
---|
305 | if(this.closeChoice==1){
|
---|
306 | this.window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
---|
307 | }
|
---|
308 | else{
|
---|
309 | this.window.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
---|
310 | }
|
---|
311 |
|
---|
312 | // Add graph canvas
|
---|
313 | this.window.getContentPane().add("Center", this);
|
---|
314 |
|
---|
315 | // Set the window up
|
---|
316 | this.window.pack();
|
---|
317 | this.window.setResizable(true);
|
---|
318 | this.window.toFront();
|
---|
319 |
|
---|
320 | // Show the window
|
---|
321 | this.window.setVisible(true);
|
---|
322 | }
|
---|
323 |
|
---|
324 |
|
---|
325 | // Set up the window, show graph and digitize (alternate spelling)
|
---|
326 | public void digitise(){
|
---|
327 | this.digitize();
|
---|
328 | }
|
---|
329 |
|
---|
330 |
|
---|
331 | // Display graph and get coordinates
|
---|
332 | private void graph(Graphics g){
|
---|
333 |
|
---|
334 | // Display graph to be digitized
|
---|
335 | g.drawImage(this.pic, 10, 30, this);
|
---|
336 | if(!this.resize){
|
---|
337 | g.drawString("RIGHT click anywhere on the screen", 5, 10);
|
---|
338 | int width = this.pic.getWidth(null);
|
---|
339 | int height = this.pic.getHeight(null);
|
---|
340 | System.out.println(width + " xxx " + height);
|
---|
341 | g.drawString(" ", 5, 10);
|
---|
342 | double factor = (double)(windowHeight-30)/(double)height;
|
---|
343 | if((int)(width*factor)>(windowWidth-10))factor = (double)(windowWidth-10)/(double)width;
|
---|
344 | height = (int)((height-30)*factor*0.95);
|
---|
345 | width = (int)((width-10)*factor+0.95);
|
---|
346 | this.pic = this.pic.getScaledInstance(width, height, Image.SCALE_DEFAULT);
|
---|
347 | g.drawImage(this.pic, 10, 30, this);
|
---|
348 | this.resize=true;
|
---|
349 | }
|
---|
350 |
|
---|
351 | // Displays cross at pixel coordinates clicked
|
---|
352 | boolean test=true;
|
---|
353 | if(this.xPos==0 && this.yPos==0)test=false;
|
---|
354 | if(test)cursorDoneSign(g, xPos, yPos);
|
---|
355 |
|
---|
356 | // Shows action required at top left of window
|
---|
357 | // and opens dialog box to input calibration points
|
---|
358 | if(!this.digitizationDone){
|
---|
359 | switch(this.iCounter){
|
---|
360 | case 0: g.drawString("RIGHT click on lower Y-axis calibration point", 5, 10);
|
---|
361 | break;
|
---|
362 | case 1: if(this.noYlow){
|
---|
363 | this.lowYvalue = Db.readDouble("Enter lower Y-axis calibration value");
|
---|
364 | this.noYlow = false;
|
---|
365 | }
|
---|
366 | g.drawString("RIGHT click on higher Y-axis calibration point", 5, 10);
|
---|
367 | break;
|
---|
368 | case 2: if(this.noYhigh){
|
---|
369 | this.highYvalue = Db.readDouble("Enter higher Y-axis calibration value");
|
---|
370 | this.noYhigh = false;
|
---|
371 | }
|
---|
372 | g.drawString("RIGHT click on lower X-axis calibration point", 5, 10);
|
---|
373 | break;
|
---|
374 | case 3: if(this.noXlow){
|
---|
375 | this.lowXvalue = Db.readDouble("Enter lower X-axis calibration value");
|
---|
376 | this.noXlow = false;
|
---|
377 | }
|
---|
378 | g.drawString("RIGHT click on higher X-axis calibration point", 5, 10);
|
---|
379 | break;
|
---|
380 | case 4: if(this.noXhigh){
|
---|
381 | this.highXvalue = Db.readDouble("Enter higher X-axis calibration value");
|
---|
382 | this.noXhigh = false;
|
---|
383 | }
|
---|
384 | g.drawString("LEFT click on points to be digitized [right click when finished digitizing]", 5, 10);
|
---|
385 | break;
|
---|
386 | default:g.drawString("LEFT click on points to be digitized [right click when finished digitizing]", 5, 10);
|
---|
387 | }
|
---|
388 | }
|
---|
389 | else{
|
---|
390 | g.drawString("You may now close this window", 5, 10);
|
---|
391 | }
|
---|
392 | }
|
---|
393 |
|
---|
394 | private void cursorDoneSign(Graphics g, int x, int y){
|
---|
395 | g.drawLine(x-5, y, x+5, y);
|
---|
396 | g.drawLine(x, y-5, x, y+5);
|
---|
397 | g.fillOval(x-3, y-3, 7, 7);
|
---|
398 | }
|
---|
399 |
|
---|
400 | // This method will be called when the mouse has been clicked.
|
---|
401 | public void mouseClicked(MouseEvent me) {
|
---|
402 |
|
---|
403 | if(!this.digitizationDone){
|
---|
404 | switch(this.iCounter){
|
---|
405 | // Low y-axis calibration point
|
---|
406 | case 0: this.xPos = me.getX();
|
---|
407 | this.yPos = me.getY();
|
---|
408 |
|
---|
409 | // identify left (1) or right (3) hand mouse click
|
---|
410 | this.button = me.getButton();
|
---|
411 | // add to sum
|
---|
412 | if(this.button==1){
|
---|
413 | this.sumX += this.xPos;
|
---|
414 | this.sumY += this.yPos;
|
---|
415 | this.iSum++;
|
---|
416 | }
|
---|
417 | else if(this.button==3){
|
---|
418 | this.sumX += this.xPos;
|
---|
419 | this.sumY += this.yPos;
|
---|
420 | this.iSum++;
|
---|
421 | this.lowYaxisXpixel = (double)this.sumX/(double)this.iSum;
|
---|
422 | this.lowYaxisYpixel = (double)this.windowHeight - (double)this.sumY/(double)this.iSum;
|
---|
423 | this.iCounter++;
|
---|
424 | this.sumX = 0;
|
---|
425 | this.sumY = 0;
|
---|
426 | this.iSum = 0;
|
---|
427 | }
|
---|
428 |
|
---|
429 | break;
|
---|
430 | // High y-axis calibration point
|
---|
431 | case 1: this.xPos = me.getX();
|
---|
432 | this.yPos = me.getY();
|
---|
433 |
|
---|
434 | // identify left (1) or right (3) hand mouse click
|
---|
435 | this.button = me.getButton();
|
---|
436 | // add to sum
|
---|
437 | if(this.button==1){
|
---|
438 | this.sumX += this.xPos;
|
---|
439 | this.sumY += this.yPos;
|
---|
440 | this.iSum++;
|
---|
441 | }
|
---|
442 | else if(this.button==3){
|
---|
443 | this.sumX += this.xPos;
|
---|
444 | this.sumY += this.yPos;
|
---|
445 | this.iSum++;
|
---|
446 | this.highYaxisXpixel = (double)this.sumX/(double)this.iSum;
|
---|
447 | this.highYaxisYpixel = (double)this.windowHeight - (double)this.sumY/(double)this.iSum;
|
---|
448 | this.iCounter++;
|
---|
449 | this.sumX = 0;
|
---|
450 | this.sumY = 0;
|
---|
451 | this.iSum = 0;
|
---|
452 | }
|
---|
453 | break;
|
---|
454 | // Low x-axis calibration point
|
---|
455 | case 2: this.xPos = me.getX();
|
---|
456 | this.yPos = me.getY();
|
---|
457 |
|
---|
458 | // identify left (1) or right (3) hand mouse click
|
---|
459 | this.button = me.getButton();
|
---|
460 | // add to sum
|
---|
461 | if(this.button==1){
|
---|
462 | this.sumX += this.xPos;
|
---|
463 | this.sumY += this.yPos;
|
---|
464 | this.iSum++;
|
---|
465 | }
|
---|
466 | else if(this.button==3){
|
---|
467 | this.sumX += this.xPos;
|
---|
468 | this.sumY += this.yPos;
|
---|
469 | this.iSum++;
|
---|
470 | this.lowXaxisXpixel = (double)this.sumX/(double)this.iSum;
|
---|
471 | this.lowXaxisYpixel = (double)this.windowHeight - (double)this.sumY/(double)this.iSum;
|
---|
472 | this.iCounter++;
|
---|
473 | this.sumX = 0;
|
---|
474 | this.sumY = 0;
|
---|
475 | this.iSum = 0;
|
---|
476 | }
|
---|
477 | break;
|
---|
478 | // High x-axis calibration point
|
---|
479 | case 3: this.xPos = me.getX();
|
---|
480 | this.yPos = me.getY();
|
---|
481 |
|
---|
482 | // identify left (1) or right (3) hand mouse click
|
---|
483 | this.button = me.getButton();
|
---|
484 | // add to sum
|
---|
485 |
|
---|
486 | PixelGrabber pixelGrabber=new PixelGrabber(pic, this.xPos, this.yPos, 1, 1, false);
|
---|
487 |
|
---|
488 | if(this.button==1){
|
---|
489 | this.sumX += this.xPos;
|
---|
490 | this.sumY += this.yPos;
|
---|
491 | this.iSum++;
|
---|
492 | }
|
---|
493 | else if(this.button==3){
|
---|
494 | this.sumX += this.xPos;
|
---|
495 | this.sumY += this.yPos;
|
---|
496 | this.iSum++;
|
---|
497 | this.highXaxisXpixel = (double)this.sumX/(double)this.iSum;
|
---|
498 | this.highXaxisYpixel = (double)this.windowHeight - (double)this.sumY/(double)this.iSum;
|
---|
499 | this.iCounter++;
|
---|
500 | this.sumX = 0;
|
---|
501 | this.sumY = 0;
|
---|
502 | this.iSum = 0;
|
---|
503 | }
|
---|
504 | break;
|
---|
505 | // Data points
|
---|
506 | default:
|
---|
507 | this.xPos = me.getX();
|
---|
508 | this.yPos = me.getY();
|
---|
509 |
|
---|
510 | // identify left (1) or right (3) hand mouse click
|
---|
511 | this.button = me.getButton();
|
---|
512 | if(this.button==1){
|
---|
513 | this.xAndYvalues.add(new Integer(this.xPos));
|
---|
514 | this.xAndYvalues.add(new Integer(this.yPos));
|
---|
515 | }
|
---|
516 |
|
---|
517 | // close file if right button clicked
|
---|
518 | if(this.button==3 && this.xAndYvalues.size()/2!=0){
|
---|
519 | this.outputData();
|
---|
520 | this.digitizationDone = true;
|
---|
521 | }
|
---|
522 | }
|
---|
523 | }
|
---|
524 |
|
---|
525 | //show the results of the click
|
---|
526 | repaint();
|
---|
527 | }
|
---|
528 |
|
---|
529 | // Output data to file and to graph
|
---|
530 | private void outputData(){
|
---|
531 |
|
---|
532 | // dimension arrays
|
---|
533 | this.nData = this.xAndYvalues.size()/2;
|
---|
534 | System.out.println("nData " + this.nData);
|
---|
535 | this.xPositions = new double[this.nData];
|
---|
536 | this.yPositions = new double[this.nData];
|
---|
537 | this.xPosPixel = new double[this.nData];
|
---|
538 | this.yPosPixel = new double[this.nData];
|
---|
539 |
|
---|
540 | int ii = 0;
|
---|
541 | // Convert pixel values to doubles
|
---|
542 | for(int i=0; i<this.nData; i++){
|
---|
543 | int xx = this.xAndYvalues.get(ii);
|
---|
544 | ii++;
|
---|
545 | int yy = this.xAndYvalues.get(ii);
|
---|
546 | ii++;
|
---|
547 | this.xPosPixel[i] = (double)xx;
|
---|
548 | this.yPosPixel[i] = (double)this.windowHeight - (double)yy;
|
---|
549 | }
|
---|
550 |
|
---|
551 | // Check if graph axes are to be rotated and, if so, rotate
|
---|
552 | this.checkForRotation();
|
---|
553 |
|
---|
554 | // Scale the pixel values to true values
|
---|
555 | for(int i=0; i<this.nData; i++){
|
---|
556 | this.xPositions[i] = this.lowXvalue + (this.xPosPixel[i] - this.lowXaxisXpixel)*(this.highXvalue - this.lowXvalue)/(this.highXaxisXpixel - this.lowXaxisXpixel);
|
---|
557 | this.yPositions[i] = this.lowYvalue + (this.yPosPixel[i] - this.lowYaxisYpixel)*(this.highYvalue - this.lowYvalue)/(this.highYaxisYpixel - this.lowYaxisYpixel);
|
---|
558 | }
|
---|
559 |
|
---|
560 | // Check for identical points and remove one of all pairs of such points
|
---|
561 | if(this.noIdentical)this.checkForIdenticalPoints();
|
---|
562 |
|
---|
563 | // Request to increase number of data points using a cubic spline interpolation
|
---|
564 | String message = "Do you wish to increase number of data points\n";
|
---|
565 | message += "using cubic spline interpolation?";
|
---|
566 | boolean opt = Db.noYes(message);
|
---|
567 | if(opt){
|
---|
568 | this.nInterpPoints = Db.readInt("Enter number of interpolation points", 200);
|
---|
569 | interpolation();
|
---|
570 | this.interpOpt = true;
|
---|
571 | }
|
---|
572 | else{
|
---|
573 | if(plotOpt)plotDigitisedPoints();
|
---|
574 | }
|
---|
575 |
|
---|
576 | // Output digitized data
|
---|
577 | this.fout.println("Digitization output for DigiGraph class (M. T. Flanagan Java Library)");
|
---|
578 | this.fout.println();
|
---|
579 | this.fout.dateAndTimeln();
|
---|
580 | this.fout.println();
|
---|
581 | this.fout.println("Image used in the digitization: " + this.imageName);
|
---|
582 | this.fout.println("Location of the image used in the digitization: " + this.imagePath);
|
---|
583 | this.fout.println();
|
---|
584 | this.fout.println("X-axis skew angle " + Fmath.truncate(this.angleXaxis, 4) + " degrees");
|
---|
585 | this.fout.println("Y-axis skew angle " + Fmath.truncate(this.angleYaxis, 4) + " degrees");
|
---|
586 | this.fout.println("Axes mean skew angle " + Fmath.truncate(this.angleMean, 4) + " degrees");
|
---|
587 | if(this.rotationDone){
|
---|
588 | this.fout.println("Axes and all points rotated to bring axes to normal position");
|
---|
589 | }
|
---|
590 | else{
|
---|
591 | this.fout.println("No rotation of axes or points performed");
|
---|
592 | }
|
---|
593 | this.fout.println();
|
---|
594 | this.fout.println("Number of digitized points: " + this.nData);
|
---|
595 | this.fout.println();
|
---|
596 | this.fout.printtab("X-value");
|
---|
597 | this.fout.println("Y-value");
|
---|
598 |
|
---|
599 | for(int i=0; i<this.nData; i++){
|
---|
600 | this.fout.printtab(Fmath.truncate(this.xPositions[i], trunc));
|
---|
601 | this.fout.println(Fmath.truncate(this.yPositions[i], trunc));
|
---|
602 | }
|
---|
603 | this.fout.println();
|
---|
604 |
|
---|
605 | // Output interpolated data if calculated
|
---|
606 | if(this.interpOpt){
|
---|
607 | this.fout.println();
|
---|
608 | this.fout.println("Interpolated data (cubic spline)");
|
---|
609 | this.fout.println();
|
---|
610 | this.fout.println("Number of interpolated points: " + this.nInterpPoints);
|
---|
611 | this.fout.println();
|
---|
612 | this.fout.printtab("X-value");
|
---|
613 | this.fout.println("Y-value");
|
---|
614 | for(int i=0; i<this.nInterpPoints; i++){
|
---|
615 | this.fout.printtab(Fmath.truncate(this.xInterp[i], trunc));
|
---|
616 | this.fout.println(Fmath.truncate(this.yInterp[i], trunc));
|
---|
617 | }
|
---|
618 | }
|
---|
619 |
|
---|
620 | this.fout.close();
|
---|
621 | }
|
---|
622 |
|
---|
623 | // Check for axes rotation
|
---|
624 | private void checkForRotation(){
|
---|
625 | double tangent = (this.highYaxisXpixel - this.lowYaxisXpixel)/(this.highYaxisYpixel - this.lowYaxisYpixel);
|
---|
626 | this.angleYaxis = Math.toDegrees(Math.atan(tangent));
|
---|
627 | tangent = (this.lowXaxisYpixel - this.highXaxisYpixel)/(this.highXaxisXpixel - this.lowXaxisXpixel);
|
---|
628 | this.angleXaxis = Math.toDegrees(Math.atan(tangent));
|
---|
629 | this.angleMean = (this.angleXaxis + this.angleYaxis)/2.0;
|
---|
630 | double absMean = Math.abs(this.angleMean);
|
---|
631 | if(absMean!=0.0 && absMean>this.angleTolerance)performRotation();
|
---|
632 | }
|
---|
633 |
|
---|
634 | // Rotate axes and all points
|
---|
635 | private void performRotation(){
|
---|
636 | // Find pixel zero-zero origin
|
---|
637 | double tangentX = (this.highXaxisYpixel - this.lowXaxisYpixel)/(this.highXaxisXpixel - this.lowXaxisXpixel);
|
---|
638 | double interceptX = this.highXaxisYpixel - tangentX*this.highXaxisXpixel;
|
---|
639 | double tangentY = (this.highYaxisYpixel - this.lowYaxisYpixel)/(this.highYaxisXpixel - this.lowYaxisXpixel);
|
---|
640 | double interceptY = this.highYaxisYpixel - tangentY*this.highYaxisXpixel;
|
---|
641 | double originX = (interceptX - interceptY)/(tangentY - tangentX);
|
---|
642 | double originY = tangentY*originX + interceptY;
|
---|
643 |
|
---|
644 | // Rotate axes calibration points
|
---|
645 | double angleMeanRad = Math.toRadians(this.angleMean);
|
---|
646 | double cosphi = Math.cos(-angleMeanRad);
|
---|
647 | double sinphi = Math.sin(-angleMeanRad);
|
---|
648 | double highXaxisXpixelR = (this.highXaxisXpixel-originX)*cosphi + (this.highXaxisYpixel-originY)*sinphi + originX;
|
---|
649 | double highXaxisYpixelR = -(this.highXaxisXpixel-originX)*sinphi + (this.highXaxisYpixel-originY)*cosphi + originY;
|
---|
650 | double lowXaxisXpixelR = (this.lowXaxisXpixel-originX)*cosphi + (this.lowXaxisYpixel-originY)*sinphi + originX;
|
---|
651 | double lowXaxisYpixelR = -(this.lowXaxisXpixel-originX)*sinphi + (this.lowXaxisYpixel-originY)*cosphi + originY;
|
---|
652 | double highYaxisXpixelR = (this.highYaxisXpixel-originX)*cosphi + (this.highYaxisYpixel-originY)*sinphi + originX;
|
---|
653 | double highYaxisYpixelR = -(this.highYaxisXpixel-originX)*sinphi + (this.highYaxisYpixel-originY)*cosphi + originY;
|
---|
654 | double lowYaxisXpixelR = -(this.lowYaxisXpixel-originX)*cosphi + (this.lowYaxisYpixel-originY)*sinphi + originX;
|
---|
655 | double lowYaxisYpixelR = (this.lowYaxisXpixel-originX)*sinphi + (this.lowYaxisYpixel-originY)*cosphi + originY;
|
---|
656 |
|
---|
657 | this.highXaxisXpixel = highXaxisXpixelR;
|
---|
658 | this.highXaxisYpixel = highXaxisYpixelR;
|
---|
659 | this.lowXaxisXpixel = lowXaxisXpixelR;
|
---|
660 | this.lowXaxisYpixel = lowXaxisYpixelR;
|
---|
661 | this.highYaxisXpixel = highYaxisXpixelR;
|
---|
662 | this.highYaxisYpixel = highYaxisYpixelR;
|
---|
663 | this.lowYaxisXpixel = lowYaxisXpixelR;
|
---|
664 | this.lowYaxisYpixel = lowYaxisYpixelR;
|
---|
665 |
|
---|
666 | // Rotate data points
|
---|
667 | for(int i=0; i<this.nData; i++){
|
---|
668 | double xx = (this.xPosPixel[i]-originX)*cosphi + (this.yPosPixel[i]-originY)*sinphi + originX;
|
---|
669 | double yy = -(this.xPosPixel[i]-originX)*sinphi + (this.yPosPixel[i]-originY)*cosphi + originY;
|
---|
670 | this.xPosPixel[i] = xx;
|
---|
671 | this.yPosPixel[i] = yy;
|
---|
672 | }
|
---|
673 |
|
---|
674 | this.rotationDone = true;
|
---|
675 | }
|
---|
676 |
|
---|
677 | // This is called when the mouse has been pressed
|
---|
678 | // since it is empty nothing happens here.
|
---|
679 | public void mousePressed (MouseEvent me) {}
|
---|
680 |
|
---|
681 | // This is called when the mouse has been released
|
---|
682 | // since it is empty nothing happens here.
|
---|
683 | public void mouseReleased (MouseEvent me) {}
|
---|
684 |
|
---|
685 | // This is executed when the mouse enters the object.
|
---|
686 | // It will only be executed again when the mouse has left and then re-entered.
|
---|
687 | public void mouseEntered (MouseEvent me) {
|
---|
688 | this.mouseEntered = true;
|
---|
689 | repaint();
|
---|
690 | }
|
---|
691 |
|
---|
692 | // This is executed when the mouse leaves the object.
|
---|
693 | public void mouseExited (MouseEvent me) {
|
---|
694 | this.mouseEntered = false;
|
---|
695 | repaint();
|
---|
696 | }
|
---|
697 |
|
---|
698 | // Performs a cubic spline interpolation on the digitized points
|
---|
699 | private void interpolation(){
|
---|
700 | // Dimension interpolation arrasys
|
---|
701 | this.xInterp = new double[this.nInterpPoints];
|
---|
702 | this.yInterp = new double[this.nInterpPoints];
|
---|
703 |
|
---|
704 | // Calculate x-axis interpolation points
|
---|
705 | double incr = (this.xPositions[this.nData-1] - this.xPositions[0])/(this.nInterpPoints - 1);
|
---|
706 | this.xInterp[0] = this.xPositions[0];
|
---|
707 | for(int i=1; i<this.nInterpPoints-1; i++){
|
---|
708 | this.xInterp[i] = this.xInterp[i-1] + incr;
|
---|
709 | }
|
---|
710 | this.xInterp[this.nInterpPoints-1] = this.xPositions[this.nData-1];
|
---|
711 |
|
---|
712 | CubicSpline cs = new CubicSpline(this.xPositions, this.yPositions);
|
---|
713 |
|
---|
714 | // Interpolate y values
|
---|
715 | for(int i=0; i<this.nInterpPoints; i++)this.yInterp[i] = cs.interpolate(this.xInterp[i]);
|
---|
716 |
|
---|
717 | // Plot interpolated curve
|
---|
718 | if(this.plotOpt){
|
---|
719 | int nMax = Math.max(this.nInterpPoints, this.nData);
|
---|
720 | double[][] plotData = PlotGraph.data(2, nMax);
|
---|
721 |
|
---|
722 | plotData[0] = this.xPositions;
|
---|
723 | plotData[1] = this.yPositions;
|
---|
724 | plotData[2] = this.xInterp;
|
---|
725 | plotData[3] = this.yInterp;
|
---|
726 |
|
---|
727 | PlotGraph pg = new PlotGraph(plotData);
|
---|
728 |
|
---|
729 | pg.setGraphTitle("Cubic Spline Interpolation of Digitised Points");
|
---|
730 | pg.setGraphTitle2(this.imagePath);
|
---|
731 |
|
---|
732 | pg.setXaxisLegend("x");
|
---|
733 | pg.setYaxisLegend("y");
|
---|
734 |
|
---|
735 | int[] lineOpt = {0, 3};
|
---|
736 | pg.setLine(lineOpt);
|
---|
737 | int[] pointOpt = {4, 0};
|
---|
738 | pg.setPoint(pointOpt);
|
---|
739 |
|
---|
740 | pg.plot();
|
---|
741 |
|
---|
742 | }
|
---|
743 | }
|
---|
744 |
|
---|
745 | // Checks for and removes all but one of identical points
|
---|
746 | public void checkForIdenticalPoints(){
|
---|
747 | int nP = this.nData;
|
---|
748 | boolean test1 = true;
|
---|
749 | int ii = 0;
|
---|
750 | while(test1){
|
---|
751 | boolean test2 = true;
|
---|
752 | int jj = ii+1;
|
---|
753 | while(test2){
|
---|
754 | System.out.println("ii " + ii + " jj " + jj);
|
---|
755 | if(this.xPositions[ii]==this.xPositions[jj] && this.yPositions[ii]==this.yPositions[jj]){
|
---|
756 | System.out.print("Class DigiGraph: two identical points, " + this.xPositions[ii] + ", " + this.yPositions[ii]);
|
---|
757 | System.out.println(", in data array at indices " + ii + " and " + jj + ", one point removed");
|
---|
758 |
|
---|
759 | for(int i=jj; i<nP; i++){
|
---|
760 | this.xPositions[i-1] = this.xPositions[i];
|
---|
761 | this.yPositions[i-1] = this.yPositions[i];
|
---|
762 | }
|
---|
763 | nP--;
|
---|
764 | if((nP-1)==ii)test2 = false;
|
---|
765 | }
|
---|
766 | else{
|
---|
767 | jj++;
|
---|
768 | if(jj>=nP)test2 = false;
|
---|
769 | }
|
---|
770 | }
|
---|
771 | ii++;
|
---|
772 | if(ii>=nP-1)test1 = false;
|
---|
773 | }
|
---|
774 |
|
---|
775 | // Repack arrays if points deleted
|
---|
776 | if(nP!=this.nData){
|
---|
777 | double[] holdX = new double[nP];
|
---|
778 | double[] holdY = new double[nP];
|
---|
779 | for(int i=0; i<nP; i++){
|
---|
780 | holdX[i] = this.xPositions[i];
|
---|
781 | holdY[i] = this.yPositions[i];
|
---|
782 | }
|
---|
783 | this.xPositions = holdX;
|
---|
784 | this.yPositions = holdY;
|
---|
785 | this.nData = nP;
|
---|
786 | }
|
---|
787 | }
|
---|
788 |
|
---|
789 | // Plots the digitized points
|
---|
790 | private void plotDigitisedPoints(){
|
---|
791 |
|
---|
792 | // Plot interpolated curve
|
---|
793 | double[][] plotData = PlotGraph.data(1, this.nData);
|
---|
794 |
|
---|
795 | plotData[0] = this.xPositions;
|
---|
796 | plotData[1] = this.yPositions;
|
---|
797 |
|
---|
798 | PlotGraph pg = new PlotGraph(plotData);
|
---|
799 |
|
---|
800 | pg.setGraphTitle("Plot of the Digitised Points");
|
---|
801 | pg.setGraphTitle2(this.imagePath);
|
---|
802 |
|
---|
803 | pg.setXaxisLegend("x");
|
---|
804 | pg.setYaxisLegend("y");
|
---|
805 |
|
---|
806 | int[] lineOpt = {0};
|
---|
807 | pg.setLine(lineOpt);
|
---|
808 | int[] pointOpt = {4};
|
---|
809 | pg.setPoint(pointOpt);
|
---|
810 |
|
---|
811 | pg.plot();
|
---|
812 | }
|
---|
813 | }
|
---|
814 |
|
---|
815 |
|
---|
816 |
|
---|