... | ... | @@ -31,7 +31,7 @@ Although it was not technically required by the assignment instructions, we want |
|
|
|
|
|
Specifically, we wanted to allow user input for these decisions:
|
|
|
|
|
|
<details><summary> 1. Allow the user to accept the default directory or set a new one.
|
|
|
<details><summary> 1. Allow the user to either accept the default directory or set a new one.
|
|
|
</summary>
|
|
|
|
|
|
```java
|
... | ... | @@ -155,7 +155,7 @@ static void askUser2() { |
|
|
|
|
|
|
|
|
|
|
|
## Conceptualisation and Creating a Main Executable Class
|
|
|
## Conceptualisation
|
|
|
|
|
|
### Concept
|
|
|
|
... | ... | @@ -173,11 +173,10 @@ As stated above, we aimed to make the whole programme run smoothly without the u |
|
|
|
|
|
```java
|
|
|
|
|
|
package eot_Sahinovic_Woehs_Zorenboehmer;
|
|
|
|
|
|
public class GoogleEarthTweetMapper {
|
|
|
|
|
|
public static String directory = "C:\\Users\\Public\\Documents";
|
|
|
// method to ask user for directory called at start, since subsequent variables require the "directory"
|
|
|
public static String directory = User_input.askUser1();
|
|
|
public static String google_earth_filepath = "C:\\Program Files\\Google\\Google Earth Pro\\client\\googleearth.exe";
|
|
|
|
|
|
public static String wms_url ="http://maps.heigit.org/osm-wms/service?service=WMS&request=GetCapabilities&version=1.1.0";
|
... | ... | @@ -186,85 +185,132 @@ public class GoogleEarthTweetMapper { |
|
|
|
|
|
public static String twitter_url = "http://www.berndresch.com/work/twitter.csv";
|
|
|
public static String twitter_csv = directory + "\\tweets.csv";
|
|
|
public static String twitter_kml = directory + "\\tweets.kml";
|
|
|
public static String twitter_polygon_kml = directory + "\\tweets_polygons.kml";
|
|
|
public static String twitter_kml = directory + "\\tweets_polygons.kml";
|
|
|
|
|
|
public static String tour_kml = directory + "\\A Little Tour of our Project.kml";
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
// Welcome, inform user of local directory and ask to proceed
|
|
|
userInput1.askUser();
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
// getMap and store locally
|
|
|
wms_GetMap.getMap();
|
|
|
// Get WMS Map and store locally
|
|
|
WMS_GetMap.getMap();
|
|
|
System.out.println(" --- Step 1 completed. ---\n");
|
|
|
|
|
|
// Turn WMS into KML
|
|
|
wms_ImageToKML.wmsTOkml();
|
|
|
WMS_ImageToKML.wmsTOkml();
|
|
|
System.out.println(" --- Step 2 completed. --- \n");
|
|
|
|
|
|
// Download tweets CSV from web
|
|
|
tweets_download.downloadCSV();
|
|
|
// Download tweets.csv from web
|
|
|
Tweets_download.downloadCSV();
|
|
|
System.out.println(" --- Step 3 completed. --- \n");
|
|
|
|
|
|
// Access local CSV tweets file and turn into KML
|
|
|
tweets_CSVtoKML.CSVtoKML();
|
|
|
// Access local tweets.csv file, convert and store as KML file
|
|
|
Tweets_polygons.tweetsToPolygons();
|
|
|
System.out.println(" --- Step 4 completed. --- \n");
|
|
|
|
|
|
// Write and store .kml file of tour through Google Earth
|
|
|
GoogleEarth_tour.createTour();
|
|
|
System.out.println(" --- Step 5 completed. --- \n");
|
|
|
|
|
|
// Ask to proceed with launch
|
|
|
userInput2.askUser2();
|
|
|
User_input.askUser2();
|
|
|
System.out.println("Continued.\n");
|
|
|
|
|
|
// Launch
|
|
|
googleEarth_launch.launchGoogleEarth();
|
|
|
System.out.println(" --- Step 5 completed. --- \n");
|
|
|
GoogleEarth_launch.launchGoogleEarth();
|
|
|
System.out.println(" --- Step 6 completed. --- \n");
|
|
|
|
|
|
}
|
|
|
}
|
|
|
} // main()
|
|
|
} // class
|
|
|
```
|
|
|
|
|
|
</details>
|
|
|
|
|
|
## Step 1: Inform User, Ask for Permission to Store Files Locally
|
|
|
## User Input
|
|
|
|
|
|
In this first step we ask the user to give us the "thumbs up" for downloading the required files onto their PC. We specify the location, which is set to "C:/Users/Public/Documents", which is a default file path that can apply to any PC.
|
|
|
In this first step we ask the user to give us the "thumbs up" for downloading the required files onto their PC. We set the default directory to "C:/Users/Public/Documents", which is given on any PC. Nonetheless, we wanted to let the user specify a different directory if they prefer that.
|
|
|
|
|
|
<details><summary> See the Code for the "userInput1.java class here</summary>
|
|
|
<details><summary> See the Code for the "userInput.java class here</summary>
|
|
|
|
|
|
```java
|
|
|
package eot_Sahinovic_Woehs_Zorenboehmer;
|
|
|
|
|
|
import java.io.File;
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
public class userInput1 {
|
|
|
public class User_input {
|
|
|
|
|
|
String directory = GoogleEarthTweetMapper.directory;
|
|
|
public static String directory;
|
|
|
|
|
|
static void askUser() {
|
|
|
static String askUser1() {
|
|
|
|
|
|
Scanner askUser = new Scanner(System.in); // warning coming from non-closed scanner. Note: if we close it, subsequent scanners fail to work.
|
|
|
String answer;
|
|
|
|
|
|
// welcome and information for user
|
|
|
System.out.println("Hello! Welcome to this Google Earth Tweet and WMS Mapper!\n\n"
|
|
|
+ "This programme will:\n"
|
|
|
+ "1: download an image of Boston from a WMS\n"
|
|
|
+ "2: convert it into a KML structure\n"
|
|
|
+ "3: download a tweets.csv file from the web\n"
|
|
|
+ "4: convert it into a KML structure\n"
|
|
|
+ "5: launch both kml files in Google Earth\n\n"
|
|
|
+ "The downloaded files will be stored at C:\\Users\\Public\\Documents\n"
|
|
|
+ "If this is fine, please enter Y below and hit enter to continue! If not, we will stop the programme and you can manually change the directory at the very top of this class's code.");
|
|
|
+ "5: create a KML file for a tour in Google Earth\n"
|
|
|
+ "6: launch all kml files in Google Earth\n\n"
|
|
|
+ "By default, the downloaded files will be stored at: C:\\Users\\Public\\Documents"
|
|
|
+ "\nIf this is fine, please enter Y below and hit enter to continue! If not, enter anything else to set a new directory.");
|
|
|
|
|
|
answer = askUser.next();
|
|
|
// askUser.close();
|
|
|
String newDirectory = null;
|
|
|
|
|
|
// if yes, set directory to the default and return directory
|
|
|
if(answer.contains("Y") || answer.contains("y") || answer.contains("yes") || answer.contains("Yes")) {
|
|
|
System.out.println("Great! Lets get started!\n");
|
|
|
directory = "C:\\Users\\Public\\Documents";
|
|
|
return directory;
|
|
|
|
|
|
// else, allow user to enter directory and check if it exists. Otherwise keep asking for a valid directory.
|
|
|
} else {
|
|
|
System.out.println("Please enter a new directory below and hit enter: ");
|
|
|
Scanner askNewDirectory = new Scanner(System.in);
|
|
|
boolean exists = false; // by default, exists is set to "false"
|
|
|
while (exists != true) { // while-loop keeps asking for user input until exists is set to "true"
|
|
|
newDirectory = askNewDirectory.nextLine(); // use .nextLine() to make sure path-files with a space are read
|
|
|
File tempDir = new File(newDirectory);
|
|
|
boolean exists2 = tempDir.exists(); // check if entered directory exists
|
|
|
if (exists2 == true) { // if directory exists, set exists2 to "true"
|
|
|
exists = true; // if exists2 is "true", exists becomes "true" to exit the while loop
|
|
|
directory = newDirectory;
|
|
|
System.out.println("\nNew directory set to: " + directory + "\n");
|
|
|
} else {
|
|
|
System.out.println("\nWrong file path. Please try again.");
|
|
|
}
|
|
|
}
|
|
|
return directory;
|
|
|
}
|
|
|
} // askUser1()
|
|
|
|
|
|
|
|
|
static void askUser2() {
|
|
|
|
|
|
// ask user to proceed with google earth launch
|
|
|
Scanner askContinue = new Scanner(System.in);
|
|
|
String answer1;
|
|
|
|
|
|
System.out.println("We have created a small tour to show you the WMS and Tweets in Google Earth. It will automatically begin when Google Earth is launched.\n"
|
|
|
+ "Would you like to proceed to launch Google Earth now? Type Y for yes or anything else for no and hit enter.");
|
|
|
|
|
|
answer1 = askContinue.next();
|
|
|
askContinue.close();
|
|
|
|
|
|
// if yes, proceed with programme execution. Else, exit programme.
|
|
|
if(answer1.contains("Y") || answer1.contains("y") || answer1.contains("yes") || answer1.contains("Yes")) {
|
|
|
System.out.println("Proceeding... ");
|
|
|
} else {
|
|
|
System.out.println("We've stopped the programme. Please adjust the code and start again!");
|
|
|
System.out.println("We've ended the programme for you. If you'd like to try again, run the programme again. :)"); // Inform
|
|
|
System.exit(0);
|
|
|
}
|
|
|
|
|
|
} // askUser()
|
|
|
} // askUer2()
|
|
|
} // class
|
|
|
```
|
|
|
</details>
|
... | ... | @@ -272,7 +318,7 @@ public class userInput1 { |
|
|
|
|
|
<details><summary> See the console output </summary>
|
|
|
|
|
|
```java
|
|
|
```
|
|
|
Hello! Welcome to this Google Earth Tweet and WMS Mapper!
|
|
|
|
|
|
This programme will:
|
... | ... | @@ -280,19 +326,26 @@ This programme will: |
|
|
2: convert it into a KML structure
|
|
|
3: download a tweets.csv file from the web
|
|
|
4: convert it into a KML structure
|
|
|
5: launch both kml files in Google Earth
|
|
|
5: create a KML file for a tour in Google Earth
|
|
|
6: launch all kml files in Google Earth
|
|
|
|
|
|
The downloaded files will be stored at C:\Users\Public\Documents
|
|
|
If this is fine, please enter Y below and hit enter to continue! If not, we will stop the programme and you can manually change the directory at the very top of this class's code.
|
|
|
y
|
|
|
Great! Lets get started!
|
|
|
By default, the downloaded files will be stored at: C:\Users\Public\Documents
|
|
|
If this is fine, please enter Y below and hit enter to continue! If not, enter anything else to set a new directory.
|
|
|
k
|
|
|
Please enter a new directory below and hit enter:
|
|
|
C:\Users\Christina\Documents\Intentional_error
|
|
|
|
|
|
Wrong file path. Please try again.
|
|
|
C:\Users\Christina\Documents\Test Folder
|
|
|
|
|
|
New directory set to: C:\Users\Christina\Documents\Test Folder
|
|
|
```
|
|
|
</details>
|
|
|
|
|
|
|
|
|
## Step 2: Web Map Service
|
|
|
## Web Map Service
|
|
|
|
|
|
### 2.1: Connecting and Downloading WMS
|
|
|
### Connecting and Downloading WMS
|
|
|
|
|
|
First, we created a [non-executable class "wms_GetMap"](https://git.sbg.ac.at/s1080384/EoT/-/blob/main/Java%20Codes/Previous%20Versions%20(working%20files)/Christina%2004_07_2021/wms_GetMap.java) that contains a method `getMap()` that:
|
|
|
> 1. creates a WebMapServer object
|
... | ... | @@ -322,7 +375,7 @@ import org.geotools.ows.wms.WebMapServer; |
|
|
import org.geotools.ows.wms.request.GetMapRequest;
|
|
|
import org.geotools.ows.wms.response.GetMapResponse;
|
|
|
|
|
|
public class wms_GetMap {
|
|
|
public class WMS_GetMap {
|
|
|
|
|
|
static void getMap() {
|
|
|
|
... | ... | @@ -349,13 +402,6 @@ public class wms_GetMap { |
|
|
}
|
|
|
System.out.println("No errors in communicating with the server.");
|
|
|
|
|
|
// Access WMSCapabilities directly from the WMS. This capabilities bean is split into three sections: Service, Request, and Layer.
|
|
|
WMSCapabilities capabilities = wms.getCapabilities();
|
|
|
|
|
|
// Get information on the service
|
|
|
String serverName = capabilities.getService().getName();
|
|
|
String serverTitle = capabilities.getService().getTitle();
|
|
|
|
|
|
// Get Map Request: ask client to create a GetMapRequest object
|
|
|
GetMapRequest request = wms.createGetMapRequest();
|
|
|
|
... | ... | @@ -369,22 +415,34 @@ public class wms_GetMap { |
|
|
request.setBBox("-71.13,42.32,-71.03,42.42");
|
|
|
|
|
|
// user interaction: offer additional information
|
|
|
Scanner askServiceInfo = new Scanner(System.in); //warning coming from non-closed scanner. Note: if scanner is closed subsequent scanners fail to work.
|
|
|
String answer;
|
|
|
Scanner askServiceInfo = new Scanner(System.in); // warning coming from non-closed scanner. Note: if scanner is closed subsequent scanners fail to work
|
|
|
String answer1;
|
|
|
String answer2;
|
|
|
System.out.println("\nWould you like additional information on the WMS service while the programme runs? Type Y for yes or anything else for no and hit enter.");
|
|
|
answer = askServiceInfo.next();
|
|
|
answer1 = askServiceInfo.next();
|
|
|
// askServiceInfo.close();
|
|
|
|
|
|
if(answer.contains("Y") || answer.contains("y") || answer.contains("yes") || answer.contains("Yes")) {
|
|
|
System.out.println("\tThe WMS capabilities are being retreived from a server called: " + serverName +"\n\tAnd the server's title is: " + serverTitle +"\n\t" +
|
|
|
"The requested image will be stored as a .png with dimensions of 1000 x 1000 pixels.\n\t" +
|
|
|
"The coordinate reference system is set to ESPG:4326.");
|
|
|
System.out.println("\tRequested GetMap URL: " + request.getFinalURL());
|
|
|
if(answer1.contains("Y") || answer1.contains("y") || answer1.contains("yes") || answer1.contains("Yes")) {
|
|
|
// Access WMS Capabilities directly from the WMS
|
|
|
WMSCapabilities capabilities = wms.getCapabilities();
|
|
|
System.out.println("\tThe WMS capabilities are being retreived from a server called: " + capabilities.getService().getName() + "\n\t" // method to access service infos
|
|
|
+ "The server's title is: " + capabilities.getService().getTitle() +"\n\t"
|
|
|
+ "The requested image will be stored as a .png with dimensions of 1000 x 1000 pixels.\n\t"
|
|
|
+ "The coordinate reference system is set to ESPG:4326.\n\t"
|
|
|
+ "The requested GetMap URL is: " + request.getFinalURL());
|
|
|
|
|
|
System.out.println("\nPlease let us know when you are done with this step. Type any keyword and press enter:");
|
|
|
Scanner askNextStep = new Scanner(System.in);
|
|
|
answer2 = askNextStep.next();
|
|
|
// if(answer2.length() != 0){
|
|
|
// }else {
|
|
|
// }
|
|
|
|
|
|
} else {
|
|
|
System.out.println("Alright.");
|
|
|
System.out.println("Alright."); // lowkey annoyed answer hehe ;)
|
|
|
}
|
|
|
|
|
|
// get response and store as .png locally
|
|
|
try {
|
|
|
GetMapResponse response = (GetMapResponse) wms.issueRequest(request);
|
|
|
BufferedImage image = ImageIO.read(response.getInputStream());
|
... | ... | @@ -394,11 +452,10 @@ public class wms_GetMap { |
|
|
} catch (ServiceException e) {
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
System.out.println("\nImage was successfully saved at: " + wms_png);
|
|
|
System.out.println("\nImage was successfully saved at: " + wms_png); // Inform
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
} // getMap()
|
|
|
} // class
|
|
|
```
|
|
|
|
|
|
</details>
|
... | ... | @@ -409,16 +466,18 @@ public class wms_GetMap { |
|
|
```
|
|
|
Testing Heigit's wms service URL... No errors in communicating with the server.
|
|
|
|
|
|
|
|
|
Would you like additional information on the WMS service while the programme runs? Type Y for yes or anything else for no and hit enter.
|
|
|
y
|
|
|
yes
|
|
|
The WMS capabilities are being retreived from a server called: OGC:WMS
|
|
|
And the server's title is :OSM-WMS Uni Heidelberg.
|
|
|
The server's title is: OSM-WMS Uni Heidelberg
|
|
|
The requested image will be stored as a .png with dimensions of 1000 x 1000 pixels.
|
|
|
The coordinate reference system is set to ESPG:4326
|
|
|
Requested GetMap URL: http://maps.heigit.org/osm-wms/service?REQUEST=GetMap&FORMAT=image%2Fpng&SRS=EPSG:4326&BBOX=-71.13,42.32,-71.03,42.42&VERSION=1.1.1&STYLES=default&SERVICE=WMS&WIDTH=1000&HEIGHT=1000&TRANSPARENT=TRUE&LAYERS=osm_auto%3Aall
|
|
|
The coordinate reference system is set to ESPG:4326.
|
|
|
The requested GetMap URL is: http://maps.heigit.org/osm-wms/service?REQUEST=GetMap&FORMAT=image%2Fpng&SRS=EPSG:4326&BBOX=-71.13,42.32,-71.03,42.42&VERSION=1.1.1&STYLES=default&SERVICE=WMS&WIDTH=1000&HEIGHT=1000&TRANSPARENT=TRUE&LAYERS=osm_auto%3Aall
|
|
|
|
|
|
Image was successfully saved at: C:\Users\Public\Documents\boston.png
|
|
|
Please let us know when you are done with this step. Type any keyword and press enter:
|
|
|
ok
|
|
|
|
|
|
Image was successfully saved at: C:\Users\Christina\Documents\Test Folder\boston.png
|
|
|
--- Step 1 completed. ---
|
|
|
|
|
|
```
|
... | ... | @@ -430,7 +489,7 @@ The result is this image "boston.png": |
|
|
|
|
|

|
|
|
|
|
|
### 2.2: Converting WMS Image into .KML
|
|
|
### Converting WMS Image into .KML
|
|
|
|
|
|
Here, we created a [non-executable class "wms_ImageToKML"](https://git.sbg.ac.at/s1080384/EoT/-/blob/main/Java%20Codes/Previous%20Versions%20(working%20files)/Christina%2004_07_2021/wms_ImageToKML.java) that contains a method `wmsTOkml()` that:
|
|
|
|
... | ... | @@ -441,32 +500,31 @@ Here, we created a [non-executable class "wms_ImageToKML"](https://git.sbg.ac.at |
|
|
|
|
|
```java
|
|
|
|
|
|
package Test2;
|
|
|
package eot_Sahinovic_Woehs_Zorenboehmer;
|
|
|
|
|
|
import java.io.File;
|
|
|
import java.io.FileWriter;
|
|
|
import java.io.IOException;
|
|
|
|
|
|
public class wms_ImageToKML {
|
|
|
public class WMS_ImageToKML {
|
|
|
|
|
|
static void wmsTOkml() {
|
|
|
|
|
|
String wms_kml = GoogleEarthTweetMapper.wms_kml;
|
|
|
String wms_png = GoogleEarthTweetMapper.wms_png;
|
|
|
|
|
|
String wms_kml = execute_programme.wms_kml;
|
|
|
String wms_png = execute_programme.wms_png;
|
|
|
|
|
|
System.out.println("Turning local .png of Boston into kml format at: " + wms_kml + "... ");
|
|
|
System.out.println("Turning local .png of Boston into kml format ... "); // Inform
|
|
|
|
|
|
// find image of boston on local PC:
|
|
|
// find stored boston.png image
|
|
|
File wms_image = new File(wms_png);
|
|
|
if(wms_image.exists()) {
|
|
|
System.out.println("Image found..");
|
|
|
System.out.println("Image found...");
|
|
|
|
|
|
}else {
|
|
|
System.out.println("Image not found..");
|
|
|
System.out.println("Image not found.");
|
|
|
}
|
|
|
|
|
|
// write kml:
|
|
|
// KML body
|
|
|
String [] kmlArray = {"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
|
|
|
,"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\r\n"
|
|
|
," <Folder> "
|
... | ... | @@ -477,10 +535,10 @@ public class wms_ImageToKML { |
|
|
," <description>Output WMS image</description>\r\n"
|
|
|
," <color>B3ffffff</color>\r\n"
|
|
|
," <Icon>\r\n"
|
|
|
," <href>" + wms_png + "</href>\r\n"
|
|
|
," <href>" + wms_png + "</href>\r\n" // integrate boston.png
|
|
|
," </Icon>\r\n"
|
|
|
," <LatLonBox>\r\n"
|
|
|
, "<north>42.42</north>\r\n"
|
|
|
, "<north>42.42</north>\r\n" // BBOX: -71.13,42.32,-71.03,42.42
|
|
|
, "<south>42.32</south>\r\n"
|
|
|
, "<east>-71.03</east>\r\n"
|
|
|
, "<west>-71.13</west>\r\n"
|
... | ... | @@ -490,7 +548,8 @@ public class wms_ImageToKML { |
|
|
, "</Folder>"
|
|
|
, "</kml>\r\n"
|
|
|
};
|
|
|
//-71.13,42.32,-71.03,42.4 -71.13,42.32,-71.03,42.42
|
|
|
|
|
|
// write and store file locally
|
|
|
try {
|
|
|
File kml_file = new File(wms_kml);
|
|
|
kml_file.createNewFile();
|
... | ... | @@ -500,16 +559,14 @@ public class wms_ImageToKML { |
|
|
writer.write(i);
|
|
|
}
|
|
|
writer.close();
|
|
|
//System.out.println(kml_file.toString());
|
|
|
|
|
|
}catch(IOException e) {
|
|
|
System.out.println("Something went wrong in: TryCatch method");
|
|
|
System.out.println("Error while writing the boston.kml file.");
|
|
|
}
|
|
|
System.out.println("Image converted to kml and stored at: " + wms_kml);
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
} // wmsTOkml()
|
|
|
} // class
|
|
|
|
|
|
```
|
|
|
|
... | ... | @@ -519,17 +576,17 @@ public class wms_ImageToKML { |
|
|
<details><summary>See Console Output</summary>
|
|
|
|
|
|
```
|
|
|
Turning local .png of Boston into kml format at: C:\Users\Christina\Documents\EoT\wms_kml_structure.kml...
|
|
|
Image found..
|
|
|
Image converted to kml and stored at: C:\Users\Christina\Documents\EoT\wms_kml_structure.kml
|
|
|
Step 2 completed.
|
|
|
Turning local .png of Boston into kml format ...
|
|
|
Image found...
|
|
|
Image converted to kml and stored at: C:\Users\Christina\Documents\Test Folder\boston.kml
|
|
|
--- Step 2 completed. ---
|
|
|
```
|
|
|
</details>
|
|
|
|
|
|
|
|
|
## Step 3: Downloading and Converting Twitter.csv File
|
|
|
## Downloading and Converting Twitter.csv File
|
|
|
|
|
|
### 3.1: Downloading
|
|
|
### Downloading
|
|
|
|
|
|
Although this step was not included in the assignment instructions, we decided it would be nice for the user to not worry about having to download the .csv file themselves. Therefore we created a [non-executable class "tweets_download"](https://git.sbg.ac.at/s1080384/EoT/-/blob/main/Java%20Codes/Previous%20Versions%20(working%20files)/Christina%2004_07_2021/tweets_download.java) that contains the methods `saveFileFromUrlWithCommonsIO()` and `downloadCSV()` that:
|
|
|
|
... | ... | @@ -539,7 +596,7 @@ Although this step was not included in the assignment instructions, we decided i |
|
|
<details><summary>See the Code for the "tweets_download.java" Class</summary>
|
|
|
|
|
|
```java
|
|
|
package Test2;
|
|
|
package eot_Sahinovic_Woehs_Zorenboehmer;
|
|
|
|
|
|
import java.io.File;
|
|
|
import java.io.IOException;
|
... | ... | @@ -548,8 +605,9 @@ import java.net.URL; |
|
|
|
|
|
import org.apache.commons.io.FileUtils;
|
|
|
|
|
|
public class tweets_download {
|
|
|
public class Tweets_download {
|
|
|
|
|
|
// method for downloading .csv file from web and saving locally
|
|
|
public static void saveFileFromUrlWithCommonsIO(String fileName,
|
|
|
String fileUrl) throws MalformedURLException, IOException {
|
|
|
FileUtils.copyURLToFile(new URL(fileUrl), new File(fileName));
|
... | ... | @@ -557,13 +615,14 @@ public class tweets_download { |
|
|
|
|
|
public static void downloadCSV() {
|
|
|
|
|
|
String twitter_url = execute_programme.twitter_url;
|
|
|
String twitter_csv = execute_programme.twitter_csv;
|
|
|
String twitter_url = GoogleEarthTweetMapper.twitter_url;
|
|
|
String twitter_csv = GoogleEarthTweetMapper.twitter_csv;
|
|
|
|
|
|
System.out.println("Downloading online tweets.csv and storing locally ... ");
|
|
|
System.out.println("Downloading online tweets.csv and storing locally ... "); // Inform
|
|
|
|
|
|
try {
|
|
|
|
|
|
// call method with relevant parameters
|
|
|
saveFileFromUrlWithCommonsIO(
|
|
|
twitter_csv,
|
|
|
twitter_url);
|
... | ... | @@ -574,9 +633,10 @@ public class tweets_download { |
|
|
e.printStackTrace();
|
|
|
}
|
|
|
|
|
|
System.out.println("CSV file downloaded and stored at :" + twitter_csv);
|
|
|
}
|
|
|
}
|
|
|
System.out.println("CSV file downloaded and stored at :" + twitter_csv); // Inform
|
|
|
|
|
|
} // downloadCSV()
|
|
|
} // class
|
|
|
```
|
|
|
|
|
|
</details>
|
... | ... | @@ -586,19 +646,19 @@ public class tweets_download { |
|
|
|
|
|
```
|
|
|
Downloading online tweets.csv and storing locally ...
|
|
|
CSV file downloaded and stored at :C:\Users\Christina\Documents\EoT\tweets.csv
|
|
|
Step 3 completed.
|
|
|
CSV file downloaded and stored at :C:\Users\Christina\Documents\Test Folder\tweets.csv
|
|
|
--- Step 3 completed. ---
|
|
|
```
|
|
|
|
|
|
</details>
|
|
|
|
|
|
### 3.2: Converting .csv into .kml
|
|
|
### Converting .csv into .kml
|
|
|
|
|
|
.....
|
|
|
This step proved to be the most complex one. In the end we used two methods within the tweets_polygons.java class. The first method dynamically determines a colour-code for the placemarks depending on the time of the tweet. The second method creates a kml file that contains 3D polygons for the point locations, with pop-up boxes, time-stamps, and a colour-coded visualisation of the time of the tweet.
|
|
|
|
|
|
**Time Stamp**
|
|
|
In the process of creating this class we had to deal with a few challenges:
|
|
|
|
|
|
After some initial [research](https://developers.google.com/kml/documentation/kmlreference#timestamp) into typical kml-conform time stamps and comparing them to "created_at" column in the tweets.csv file, we chose to aim for a time stamp that was already mostly given in the .csv, but with a few differences:
|
|
|
**Time Stamp:** After some initial [research](https://developers.google.com/kml/documentation/kmlreference#timestamp) into typical kml-conform time stamps and comparing them to "created_at" column in the tweets.csv file, we chose to aim for a time stamp that was already mostly given in the .csv, but with a few differences:
|
|
|
|
|
|
> kml time stamp: 1997-07-16T10:30:15+03:00
|
|
|
|
... | ... | @@ -606,44 +666,430 @@ After some initial [research](https://developers.google.com/kml/documentation/km |
|
|
|
|
|
We therefore concluded that we needed to add in the "T" where the blank space is and add ":00" at the end.
|
|
|
|
|
|
<details><summary>This is how we created the kml-conform time stamp</summary>
|
|
|
**Creating Polygons from Points:** To solve this, we perfomed some simple math calculations on the lat and lng coordinates of the point locations. This required a few conversions of String to Double and then back into String, to insert the new coordinates into the kml body.
|
|
|
|
|
|
**Colouring the Polygons according to the Time of Tweet:** ....
|
|
|
|
|
|
|
|
|
<details><summary>See the Code for the tweets_polygons.java Class</summary>
|
|
|
|
|
|
```java
|
|
|
|
|
|
package eot_Sahinovic_Woehs_Zorenboehmer;
|
|
|
|
|
|
import java.io.BufferedReader;
|
|
|
import java.io.FileReader;
|
|
|
import java.io.FileWriter;
|
|
|
import java.io.IOException;
|
|
|
import java.text.ParseException;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
|
import java.util.Date;
|
|
|
|
|
|
public class Tweets_polygons {
|
|
|
|
|
|
// method for setting the colour according to the time
|
|
|
public static String dateToColor(Date date, Date firstDate) {
|
|
|
|
|
|
// .getTime converts to milliseconds, divide with 1000 to get seconds, additionally divide by 6 to get results within a range of 256 (required for the colouring)
|
|
|
long seconds = date.getTime() / 1000 / 6; // time of current csv row
|
|
|
long secondsFirstDate = firstDate.getTime() / 1000 / 6; // first time in tweets.csv
|
|
|
|
|
|
// convert to int and calculate time difference since "First Date"
|
|
|
int difference = (int) (seconds - secondsFirstDate);
|
|
|
|
|
|
// subtract difference from 255 (255 = maximum green colour value)
|
|
|
// this allows us to assign brighter shades to earlier times and darker shades to later times
|
|
|
int invertColor = 255 - difference%256;
|
|
|
|
|
|
// convert int into hexadecimal string
|
|
|
String changeColor = Integer.toHexString(invertColor);
|
|
|
|
|
|
// if the conversion results in a String with only 1 character, we add another character to fit the required 8-character hexadecimal string
|
|
|
if(changeColor.length() == 1) {
|
|
|
changeColor = "0" + changeColor;
|
|
|
}
|
|
|
|
|
|
// return the formatted colour which is then passed to the kml_color variable to insert into the kml body
|
|
|
// hexadecimal order = alpha(opacity) + blue + green + red
|
|
|
// we dynamically set green according to the tweet time. Opacity and red are at maximum (FF). Blue is 00. This gives dynamic colour ramp from yellow to red.
|
|
|
return "FF"+ "00" + changeColor + "FF";
|
|
|
|
|
|
} //dateToColor()
|
|
|
|
|
|
|
|
|
// method to create .kml file
|
|
|
static void tweetsToPolygons() {
|
|
|
|
|
|
String twitter_csv = GoogleEarthTweetMapper.twitter_csv;
|
|
|
String twitter_kml = GoogleEarthTweetMapper.twitter_kml;
|
|
|
ArrayList<String> kmlcontent = new ArrayList<String>();
|
|
|
String kmlcontentString = null;
|
|
|
String kml_head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
|
|
+ "<kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\" xmlns:kml=\"http://www.opengis.net/kml/2.2\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n"
|
|
|
+ "<Document>\n";
|
|
|
String kml_end = "</Document>\n"
|
|
|
+ "</kml>";
|
|
|
String line = "";
|
|
|
String splitBy = ";";
|
|
|
int count = 0;
|
|
|
|
|
|
System.out.println("Accessing local tweets.csv file and converting into kml file ..."); // Inform
|
|
|
Date firstDate = null;
|
|
|
|
|
|
// CSV columns: id; lng; lat; hashtags; place_id; tweet; created_at; user_id
|
|
|
|
|
|
try {
|
|
|
BufferedReader br = new BufferedReader(new FileReader(twitter_csv));
|
|
|
while((line = br.readLine()) != null) {
|
|
|
if(count != 0) {
|
|
|
String[] column = line.split(splitBy);
|
|
|
String[] time = column[6].split(" "); // split the "created_at" column entry by a blank space, since there is a blank where we need to add a "T"
|
|
|
kmlcontent.add("<Placemark>\n" +
|
|
|
"<name>"+ count +"</name>\n" +
|
|
|
"<description><![CDATA[\n"+ // pop-up box with some descriptions
|
|
|
"<h1>Tweet Description</h1>\n" +
|
|
|
"<span style='color:blue'>Additional Infos:</span>\n" +
|
|
|
"<table border=1>\n" +
|
|
|
"<tr><td>Hashtags </td><td>" + column[3] + "</td></tr>\n" +
|
|
|
"<tr><td>Tweet Content</td><td>" + column[5] + "</td></tr>\n" +
|
|
|
"<tr><td>Time of Tweet</td><td>" + column[6] + "</td></tr>\n" +
|
|
|
"</table>\n"+
|
|
|
"]]></description>\n" +
|
|
|
"<Point>\n" +
|
|
|
"<coordinates>" + column[1] + "," + column[2] + ",0</coordinates>\n" +
|
|
|
"</Point>\n" +
|
|
|
"<TimeStamp>\n" +
|
|
|
"<when>" + time[0] + "T" + time[1] + ":00</when>\n" + // .kml conform formatting
|
|
|
"</TimeStamp>\n" +
|
|
|
"</Placemark>\n");
|
|
|
while((line = br.readLine()) != null) { // while-loop to iterate through lines
|
|
|
if(count != 0) { // != 0 to skip the first row, which contains the column names
|
|
|
String[] column = line.split(splitBy); // split row by ;
|
|
|
String[] time = column[6].split(" "); // split the "created_at" column entry by its blank space to add in the missing "T"
|
|
|
|
|
|
// Strings for the triangle coordinates
|
|
|
String lower_right;
|
|
|
String lower_left;
|
|
|
String above;
|
|
|
|
|
|
// building blocks for the triangles based on the point coordinate in the CSV file
|
|
|
// we need "Double" data type here to perform some simple math
|
|
|
Double lower_right_lng = (Double.valueOf(column[1]) - 0.00075);
|
|
|
Double lower_right_lat = (Double.valueOf(column[2]) - 0.00025);
|
|
|
Double lower_left_lng = (Double.valueOf(column[1]) + 0.00075);
|
|
|
Double lower_left_lat = (Double.valueOf(column[2]) - 0.00025);
|
|
|
Double upper_lng = (Double.valueOf(column[1]));
|
|
|
Double upper_lat = (Double.valueOf(column[2]) + 0.00025);
|
|
|
|
|
|
// convert back into "String" data type for the KML file
|
|
|
above = Double.toString(upper_lng) + "," + Double.toString(upper_lat) + ",100\n";
|
|
|
lower_right = Double.toString(lower_right_lng) + "," + Double.toString(lower_right_lat) + ",100\n";
|
|
|
lower_left = Double.toString(lower_left_lng) + "," + Double.toString(lower_left_lat) + ",100\n";
|
|
|
|
|
|
// set dynamic colour value depending on time of tweet (see method above)
|
|
|
// parse time[1], which contains the time, to get a java-readable date format
|
|
|
String timestamp = time[1].substring(0, 8); // only read characters 0 - 8, since the last 3 characters aren't used in java
|
|
|
SimpleDateFormat date_format = new SimpleDateFormat("HH:mm:ss");
|
|
|
|
|
|
Date date = null;
|
|
|
try {
|
|
|
date = date_format.parse(timestamp);
|
|
|
} catch (ParseException e) {
|
|
|
System.err.println("There was problem with the date format.");
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
|
|
|
// The CSV file is sorted by 'created_at' column, therefore we can fetch the first (starting) date of
|
|
|
// tweets and use it to reference the seconds passed in all other tweets
|
|
|
if(count == 1) {
|
|
|
firstDate = date;
|
|
|
}
|
|
|
|
|
|
// passes the date and first date to the dateToColor() method to return a colour value according to the time passed since "firstDate"
|
|
|
String kml_color = dateToColor(date, firstDate);
|
|
|
|
|
|
// KML Body for each placemark
|
|
|
kmlcontent.add("<Style id=\"transBluePoly\">\n"
|
|
|
+ "<LineStyle>\n"
|
|
|
+ "<width>1</width>\n"
|
|
|
+ "</LineStyle>\n"
|
|
|
+ "<PolyStyle>\n"
|
|
|
+ "<color>"+ kml_color + "</color>\n" // insert dynamic colour value
|
|
|
+ "</PolyStyle>\n"
|
|
|
+ "</Style>\n"
|
|
|
+ "<Placemark>\n"
|
|
|
+ "<description><![CDATA[\n" // pop-up box with some descriptions
|
|
|
+ "<h1>Tweet Details</h1>\n"
|
|
|
+ "<span style='color:blue'>Additional Infos:</span>\n"
|
|
|
+ "<table border=1>\n"
|
|
|
+ "<tr><td>Hashtags </td><td>" + column[3] + "</td></tr>\n"
|
|
|
+ "<tr><td>Tweet Content</td><td>" + column[5] + "</td></tr>\n"
|
|
|
+ "<tr><td>Time of Tweet</td><td>" + column[6] + "</td></tr>\n"
|
|
|
+ "</table>\n"
|
|
|
+ "]]></description>\n"
|
|
|
+ "<TimeStamp>\n"
|
|
|
+ "<when>" + time[0] + "T" + time[1] + ":00</when>\n" // KML conform formatting
|
|
|
+ "</TimeStamp>\n"
|
|
|
+ "<styleUrl>#transBluePoly</styleUrl>\n"
|
|
|
+ "<Polygon>\n"
|
|
|
+ "<extrude>1</extrude>\n"
|
|
|
+ "<altitudeMode>relativeToGround</altitudeMode>\n"
|
|
|
+ "<outerBoundaryIs>\n"
|
|
|
+ "<LinearRing>\n"
|
|
|
+ "<coordinates>" + above // triangle
|
|
|
+ lower_left
|
|
|
+ lower_right
|
|
|
+ above
|
|
|
+ "</coordinates>\n"
|
|
|
+ "</LinearRing>\n"
|
|
|
+ "</outerBoundaryIs>\n"
|
|
|
+ "</Polygon>"
|
|
|
+ "</Placemark>\n");
|
|
|
}
|
|
|
|
|
|
count++; // count to keep track of how many placemarks are processed
|
|
|
}
|
|
|
br.close();
|
|
|
} catch (IOException e) {
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
|
|
|
// turn String array into one single String to then write it into a .kml file
|
|
|
for(int i=1; i < kmlcontent.size(); i++) {
|
|
|
kmlcontentString = String.join(",", kmlcontent);
|
|
|
}
|
|
|
System.out.println(count + " KML placemarks have been generated."); // Inform
|
|
|
|
|
|
// write and store file
|
|
|
try {
|
|
|
final FileWriter fw = new FileWriter(twitter_kml);
|
|
|
fw.write(kml_head + kmlcontentString + kml_end);
|
|
|
fw.close();
|
|
|
}catch (IOException e) {
|
|
|
System.out.println("error");
|
|
|
}
|
|
|
|
|
|
System.out.println("All " + count + " placemarks have been integrated into a single KML file, which is saved at " + twitter_kml); // Inform
|
|
|
|
|
|
} // tweetsToPolygons()
|
|
|
} // class
|
|
|
|
|
|
```
|
|
|
|
|
|
</details>
|
|
|
|
|
|
<details><summary>See the Console Output</summary>
|
|
|
|
|
|
```
|
|
|
Accessing local tweets.csv file and converting into kml file ...
|
|
|
1163 KML placemarks have been generated.
|
|
|
All 1163 placemarks have been integrated into a single KML file, which is saved at C:\Users\Christina\Documents\Test Folder\tweets_polygons.kml
|
|
|
--- Step 4 completed. ---
|
|
|
|
|
|
```
|
|
|
|
|
|
</details>
|
|
|
|
|
|
## Creating a KML Tour
|
|
|
|
|
|
Although not technically required, we though it would improve the user experience to be guided through the results in Google Earth. We therefore created our own KML tour and integrated it into a non-executable .java class that stores the tour.kml locally.
|
|
|
|
|
|
<details><summary>See the Code for the googleEarth_Tour.java Class</summary>
|
|
|
|
|
|
```java
|
|
|
package eot_Sahinovic_Woehs_Zorenboehmer;
|
|
|
|
|
|
import java.io.FileWriter;
|
|
|
import java.io.IOException;
|
|
|
|
|
|
public class GoogleEarth_tour {
|
|
|
|
|
|
static void createTour() {
|
|
|
|
|
|
String tour_kml = GoogleEarthTweetMapper.tour_kml;
|
|
|
|
|
|
// write and store kml file for the tour
|
|
|
try {
|
|
|
final FileWriter fw = new FileWriter(tour_kml);
|
|
|
fw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
|
|
+ "<kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\" xmlns:kml=\"http://www.opengis.net/kml/2.2\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n"
|
|
|
+ "<gx:Tour>\n"
|
|
|
+ " <name>A Little Tour of our Project</name>\n"
|
|
|
+ " <gx:Playlist>\n"
|
|
|
+ " <gx:FlyTo>\n"
|
|
|
+ " <LookAt>\n"
|
|
|
+ " <gx:horizFov>59.99999999999999</gx:horizFov>\n"
|
|
|
+ " <longitude>-63.12290854007514</longitude>\n"
|
|
|
+ " <latitude>39.71944819955333</latitude>\n"
|
|
|
+ " <altitude>0</altitude>\n"
|
|
|
+ " <heading>0.9939864428085535</heading>\n"
|
|
|
+ " <tilt>0.3786868214997998</tilt>\n"
|
|
|
+ " <range>9358161.741512068</range>\n"
|
|
|
+ " <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>\n"
|
|
|
+ " </LookAt>\n"
|
|
|
+ " </gx:FlyTo>\n"
|
|
|
+ " <gx:Wait><gx:duration>2</gx:duration>\n"
|
|
|
+ "</gx:Wait>\n"
|
|
|
+ " <gx:FlyTo>\n"
|
|
|
+ " <gx:duration>5</gx:duration>\n"
|
|
|
+ " <gx:flyToMode>smooth</gx:flyToMode>\n"
|
|
|
+ " <LookAt>\n"
|
|
|
+ " <gx:horizFov>59.99999999999999</gx:horizFov>\n"
|
|
|
+ " <longitude>-71.00888853810095</longitude>\n"
|
|
|
+ " <latitude>42.42768383617462</latitude>\n"
|
|
|
+ " <altitude>0</altitude>\n"
|
|
|
+ " <heading>11.16425128020962</heading>\n"
|
|
|
+ " <tilt>75.09594378664738</tilt>\n"
|
|
|
+ " <range>33468.75153062727</range>\n"
|
|
|
+ " <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>\n"
|
|
|
+ " </LookAt>\n"
|
|
|
+ " </gx:FlyTo>\n"
|
|
|
+ " <gx:FlyTo>\n"
|
|
|
+ " <gx:duration>7</gx:duration>\n"
|
|
|
+ " <gx:flyToMode>smooth</gx:flyToMode>\n"
|
|
|
+ " <LookAt>\n"
|
|
|
+ " <gx:horizFov>59.99999999999999</gx:horizFov>\n"
|
|
|
+ " <longitude>-71.05756219764805</longitude>\n"
|
|
|
+ " <latitude>42.36381827829531</latitude>\n"
|
|
|
+ " <altitude>0</altitude>\n"
|
|
|
+ " <heading>10.46224084333792</heading>\n"
|
|
|
+ " <tilt>73.15957923404167</tilt>\n"
|
|
|
+ " <range>16764.66828564515</range>\n"
|
|
|
+ " <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>\n"
|
|
|
+ " </LookAt>\n"
|
|
|
+ " </gx:FlyTo>\n"
|
|
|
+ " <gx:Wait><gx:duration>0</gx:duration>\n"
|
|
|
+ "</gx:Wait>\n"
|
|
|
+ " <gx:FlyTo>\n"
|
|
|
+ " <gx:duration>7</gx:duration>\n"
|
|
|
+ " <gx:flyToMode>smooth</gx:flyToMode>\n"
|
|
|
+ " <LookAt>\n"
|
|
|
+ " <gx:horizFov>59.99999999999999</gx:horizFov>\n"
|
|
|
+ " <longitude>-71.11151196070301</longitude>\n"
|
|
|
+ " <latitude>42.34727871857214</latitude>\n"
|
|
|
+ " <altitude>0</altitude>\n"
|
|
|
+ " <heading>-114.9206190297224</heading>\n"
|
|
|
+ " <tilt>79.41729683363144</tilt>\n"
|
|
|
+ " <range>13060.02547246438</range>\n"
|
|
|
+ " <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>\n"
|
|
|
+ " </LookAt>\n"
|
|
|
+ " </gx:FlyTo>\n"
|
|
|
+ " <gx:FlyTo>\n"
|
|
|
+ " <gx:duration>7</gx:duration>\n"
|
|
|
+ " <gx:flyToMode>smooth</gx:flyToMode>\n"
|
|
|
+ " <LookAt>\n"
|
|
|
+ " <gx:horizFov>59.99999999999999</gx:horizFov>\n"
|
|
|
+ " <longitude>-71.11254908336019</longitude>\n"
|
|
|
+ " <latitude>42.34841147160513</latitude>\n"
|
|
|
+ " <altitude>0</altitude>\n"
|
|
|
+ " <heading>-114.9213187114234</heading>\n"
|
|
|
+ " <tilt>79.41734701430147</tilt>\n"
|
|
|
+ " <range>13065.70842019121</range>\n"
|
|
|
+ " <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>\n"
|
|
|
+ " </LookAt>\n"
|
|
|
+ " </gx:FlyTo>\n"
|
|
|
+ " <gx:Wait><gx:duration>0</gx:duration>\n"
|
|
|
+ "</gx:Wait>\n"
|
|
|
+ " <gx:FlyTo>\n"
|
|
|
+ " <gx:duration>7</gx:duration>\n"
|
|
|
+ " <gx:flyToMode>smooth</gx:flyToMode>\n"
|
|
|
+ " <LookAt>\n"
|
|
|
+ " <gx:horizFov>59.99999999999999</gx:horizFov>\n"
|
|
|
+ " <longitude>-73.86458392265166</longitude>\n"
|
|
|
+ " <latitude>40.86813179276373</latitude>\n"
|
|
|
+ " <altitude>0</altitude>\n"
|
|
|
+ " <heading>-116.7537623780953</heading>\n"
|
|
|
+ " <tilt>75.03497476257493</tilt>\n"
|
|
|
+ " <range>27679.03348690332</range>\n"
|
|
|
+ " <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>\n"
|
|
|
+ " </LookAt>\n"
|
|
|
+ " </gx:FlyTo>\n"
|
|
|
+ " <gx:Wait><gx:duration>0</gx:duration>\n"
|
|
|
+ "</gx:Wait>\n"
|
|
|
+ " <gx:FlyTo>\n"
|
|
|
+ " <gx:duration>8</gx:duration>\n"
|
|
|
+ " <gx:flyToMode>smooth</gx:flyToMode>\n"
|
|
|
+ " <LookAt>\n"
|
|
|
+ " <gx:horizFov>59.99999999999999</gx:horizFov>\n"
|
|
|
+ " <longitude>-73.95117991181387</longitude>\n"
|
|
|
+ " <latitude>40.78966963325912</latitude>\n"
|
|
|
+ " <altitude>0</altitude>\n"
|
|
|
+ " <heading>-134.23974677664</heading>\n"
|
|
|
+ " <tilt>57.28506199682491</tilt>\n"
|
|
|
+ " <range>3118.651189787366</range>\n"
|
|
|
+ " <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>\n"
|
|
|
+ " </LookAt>\n"
|
|
|
+ " </gx:FlyTo>\n"
|
|
|
+ " <gx:Wait><gx:duration>0</gx:duration>\n"
|
|
|
+ "</gx:Wait>\n"
|
|
|
+ " <gx:FlyTo>\n"
|
|
|
+ " <gx:duration>8</gx:duration>\n"
|
|
|
+ " <gx:flyToMode>smooth</gx:flyToMode>\n"
|
|
|
+ " <LookAt>\n"
|
|
|
+ " <gx:horizFov>59.99999999999999</gx:horizFov>\n"
|
|
|
+ " <longitude>-73.99118107526316</longitude>\n"
|
|
|
+ " <latitude>40.75405954432178</latitude>\n"
|
|
|
+ " <altitude>0</altitude>\n"
|
|
|
+ " <heading>-159.7455532781321</heading>\n"
|
|
|
+ " <tilt>74.69366745565868</tilt>\n"
|
|
|
+ " <range>2796.849892250283</range>\n"
|
|
|
+ " <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>\n"
|
|
|
+ " </LookAt>\n"
|
|
|
+ " </gx:FlyTo>\n"
|
|
|
+ " <gx:Wait><gx:duration>0</gx:duration>\n"
|
|
|
+ "</gx:Wait>\n"
|
|
|
+ " <gx:FlyTo>\n"
|
|
|
+ " <gx:duration>14</gx:duration>\n"
|
|
|
+ " <gx:flyToMode>smooth</gx:flyToMode>\n"
|
|
|
+ " <LookAt>\n"
|
|
|
+ " <gx:horizFov>59.99999999999999</gx:horizFov>\n"
|
|
|
+ " <longitude>-73.99779113834319</longitude>\n"
|
|
|
+ " <latitude>40.71720996130342</latitude>\n"
|
|
|
+ " <altitude>0</altitude>\n"
|
|
|
+ " <heading>20.88076637360208</heading>\n"
|
|
|
+ " <tilt>74.3499982894479</tilt>\n"
|
|
|
+ " <range>3941.452446446386</range>\n"
|
|
|
+ " <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>\n"
|
|
|
+ " </LookAt>\n"
|
|
|
+ " </gx:FlyTo>\n"
|
|
|
+ " <gx:Wait><gx:duration>0</gx:duration>\n"
|
|
|
+ "</gx:Wait>\n"
|
|
|
+ " <gx:FlyTo>\n"
|
|
|
+ " <gx:duration>12</gx:duration>\n"
|
|
|
+ " <gx:flyToMode>smooth</gx:flyToMode>\n"
|
|
|
+ " <LookAt>\n"
|
|
|
+ " <gx:horizFov>59.99999999999999</gx:horizFov>\n"
|
|
|
+ " <longitude>-74.01685810703967</longitude>\n"
|
|
|
+ " <latitude>40.69122646445487</latitude>\n"
|
|
|
+ " <altitude>0</altitude>\n"
|
|
|
+ " <heading>20.87436197040366</heading>\n"
|
|
|
+ " <tilt>54.36565733205216</tilt>\n"
|
|
|
+ " <range>20329.19846682225</range>\n"
|
|
|
+ " <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>\n"
|
|
|
+ " </LookAt>\n"
|
|
|
+ " </gx:FlyTo>\n"
|
|
|
+ " <gx:FlyTo>\n"
|
|
|
+ " <gx:duration>5</gx:duration>\n"
|
|
|
+ " <gx:flyToMode>smooth</gx:flyToMode>\n"
|
|
|
+ " <LookAt>\n"
|
|
|
+ " <gx:horizFov>59.99999999999999</gx:horizFov>\n"
|
|
|
+ " <longitude>-74.01429117929963</longitude>\n"
|
|
|
+ " <latitude>40.68700202906096</latitude>\n"
|
|
|
+ " <altitude>0</altitude>\n"
|
|
|
+ " <heading>20.87603598047493</heading>\n"
|
|
|
+ " <tilt>54.36574872906584</tilt>\n"
|
|
|
+ " <range>20341.71715068461</range>\n"
|
|
|
+ " <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>\n"
|
|
|
+ " </LookAt>\n"
|
|
|
+ " </gx:FlyTo>\n"
|
|
|
+ " </gx:Playlist>\n"
|
|
|
+ "</gx:Tour>\n"
|
|
|
+ "</kml>\n");
|
|
|
fw.close();
|
|
|
|
|
|
}catch (IOException e) {
|
|
|
System.out.println("Error writing KML file.");
|
|
|
}
|
|
|
|
|
|
System.out.println("KML Tour created and stored at " + tour_kml); // inform
|
|
|
|
|
|
} // createTour()
|
|
|
} // class
|
|
|
|
|
|
```
|
|
|
</details>
|
|
|
|
|
|
<details><summary>See the Console Output</summary>
|
|
|
|
|
|
```
|
|
|
KML Tour created and stored at C:\Users\Christina\Documents\Test Folder\A Little Tour of our Project.kml
|
|
|
--- Step 5 completed. ---
|
|
|
|
|
|
```
|
|
|
</details>
|
|
|
|
|
|
|
|
|
## Step 4: Launch Google Earth
|
|
|
## Launch Google Earth
|
|
|
|
|
|
### 4.1: Ask User to Proceed and Launch
|
|
|
|
... | ... | |