teaching machines

Homework 6 – A-routes

Your objective in this homework is to learn how to marry data and code—or state and behaviors—into objects. You will do this in the context of writing a program that maps routes of runs in Google Earth or Google Maps. The intent of the program is to promote exercise by making available a catalog of routes that are interesting in that they trace out meaningful or humorous shapes or words. In this homework, we name such routes A-routes, or A-rts for short.

This assignment is more involved and less easy to test in small chunks than your previous assignments. Plan accordingly.

Before we dig into the specification, let’s talk about the structure of an A-route and its file format.

A-route

Consider the following file that describes an A-route:

artist Chris Johnson
name Helleau, Claire!
description
This is how I greet each day.
enddescription
leg
name h
closed false
waypoint 44.801799 -91.491848
waypoint 44.799473 -91.492579
waypoint 44.800465 -91.492256
waypoint 44.799940 -91.489048
waypoint 44.798897 -91.489402
endleg
leg
name base of i
closed false
waypoint 44.798638 -91.487889
waypoint 44.799698 -91.487546
waypoint 44.801051 -91.487363
endleg
leg
name jot of i
closed true
waypoint 44.801744 -91.487277
waypoint 44.802452 -91.487889
waypoint 44.802916 -91.486591
waypoint 44.802178 -91.486323
endleg

Let’s walk through this file in chunks. Here’s the first section:

artist Chris Johnson
name Helleau, Claire!
description
This is how I greet each day.
enddescription

This section defines who designed the A-route and gives it a meaningful name and description. Following are descriptions of the route’s three legs, like this one:

leg
name h
closed false
waypoint 44.801799 -91.491848
waypoint 44.799473 -91.492579
waypoint 44.800465 -91.492256
waypoint 44.799940 -91.489048
waypoint 44.798897 -91.489402
endleg

As suggested by the name, this leg draws a lowercase H. It is not closed; it does not end where it started. It consists of five latitude-longitude pairs, or waypoints, that define the path.

Most normal runs consist of a single leg. To support more kinds of drawing, we allow A-routes to consist of a series of disconnected legs. In a sense, each leg is a separate stroke, in between which the runner “lifts the pen.” Here, the second and third legs draw the two parts of a lowercase I.

KML

In this homework, we’ll collect a bunch of these A-routes into a directory, and our program will generate a catalog of the routes organized by artist. This catalog is expressed in the Keyhole Markup Language (KML). The name derives from Keyhole, Inc., a geoinformatics company acquired by Google in 2004 when it expanded into mapping services.

If our directory contains only the example above, our program produces the following KML file:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>A-routes by Artist</name>
<Style id="polylineStyle">
<LineStyle>
<color>7fff3333</color>
<width>4</width>
</LineStyle>
</Style>
<Folder>
<name>Chris Johnson</name>
<Folder>
<name>Helleau, Claire!</name>
<description>This is how I greet each day.</description>
<Placemark>
<name>h</name>
<styleUrl>#polylineStyle</styleUrl>
<LineString>
<coordinates>
-91.491848,44.801799
-91.492579,44.799473
-91.492256,44.800465
-91.489048,44.799940
-91.489402,44.798897
</coordinates>
</LineString>
</Placemark>
<Placemark>
<name>base of i</name>
<styleUrl>#polylineStyle</styleUrl>
<LineString>
<coordinates>
-91.487889,44.798638
-91.487546,44.799698
-91.487363,44.801051
</coordinates>
</LineString>
</Placemark>
<Placemark>
<name>jot of i</name>
<styleUrl>#polylineStyle</styleUrl>
<LineString>
<coordinates>
-91.487277,44.801744
-91.487889,44.802452
-91.486591,44.802916
-91.486323,44.802178
-91.487277,44.801744
</coordinates>
</LineString>
</Placemark>
</Folder>
</Folder>
</Document>
</kml>

When we view this file in Google Earth, we see this map:

In general, we can expect many files to be in the directory, with many artists having designed many runs. These can be navigated using the hierarchy in the left pane.

Google Maps

KML files can also be viewed in Google Maps. To load a KML file into Google Maps, follow these steps:

  • Visit maps.google.com.
  • Click on the hamburger icon (the stack of three horizontal lines) on the top-left.
  • Navigate to Your Places / Maps.
  • Click Create Map.
  • Import the KML file.

However, Google Maps doesn’t support all features of KML. In particular, it doesn’t acknowledge the hierarchical organization of the artist catalog. For this reason, we recommend downloading and testing with Google Earth.

Creating Your Own

To create your own map, handcraft an A-route file. To determine the waypoints, visit Google Maps, find some roads or trails that will support the shapes or words that you want to trace, and identify the latitude-longitude pairs by tapping on the map or right-clicking and selecting What’s Here? A small dialog will appear at the bottom of the screen. Click on the latitude-longitude, which will load a panel from which you can copy and paste the coordinates.

Requirements

Complete the classes described below. Place all classes in package hw6.

Main

Write class Main with a main method, which you are encouraged to use to test your code. Nothing in particular is required of it, but it must exist.

Waypoint

Write class Waypoint with the following methods:

  • A constructor that accepts two parameters in the following order:
    • a latitude of type double
    • a longitude of type double
  • Methods getLatitude that returns the waypoint’s latitude as a double.
  • Methods getLongitude that returns the waypoint’s longitude as a double.

Leg

Write class Leg that represents one stretch of an A-route. It encapsulates a named collection of waypoints and has the following methods:

  • A default constructor that initializes this leg of an A-route to have the name "Unnamed Leg", to not be a closed leg, and to not have any waypoints.
  • A constructor that initializes this leg of an A-route by parsing a leg specification from an A-route file. It accepts as its sole parameter a Scanner that is poised to read the leg specification. For example, it might read this text:
    name jot of i
    closed true
    waypoint 44.801744 -91.487277
    waypoint 44.802452 -91.487889
    waypoint 44.802916 -91.486591
    waypoint 44.802178 -91.486323
    endleg
    The name may consist of multiple white-space separated words. The whitespace appearing between name and the next non-space character is not included in the name. For example, the command name Figure 8 produces the name Figure 8. The name, closed, and waypoint commands may appear in any order. However, when this leg is run, the waypoints are passed through in their order of appearance. If the name or closed commands are absent, these properties take on their default values.
  • Method isClosed that returns this leg’s closed property as a boolean. A closed leg is one that ends where it started.
  • Method setClosed that accepts as its sole parameter the leg’s new closed property of type boolean.
  • Method addWaypoint that accepts as its sole parameter the next waypoint on this leg, of type Waypoint.
  • Method getWaypointCount that returns as an int the current number of waypoints on this leg.
  • Method getWaypoint that accepts as its sole parameter the index of a waypoint within this leg, of type int. It returns the Waypoint specified by the index.
  • Method toKml that accepts as its sole parameter a PrintWriter. It emits output in the following form to the PrintWriter:
    <Placemark>
    <name>NAME</name>
    <styleUrl>#polylineStyle</styleUrl>
    <LineString>
    <coordinates>
    PLACE0-LONGITUDE,PLACE0-LATITUDE
    PLACE1-LONGITUDE,PLACE1-LATITUDE
    PLACE2-LONGITUDE,PLACE2-LATITUDE
    ...
    </coordinates>
    </LineString>
    </Placemark>
    
    The capitalized words are placeholders; they should be replaced with the actual properties of this leg. The latitudes and longitudes are formatted to include 6 digits after the decimal point. If the leg is closed, the final entry of the waypoints list is waypoint 0.

Aroute

Write class Aroute that represents an A-route. It encapsulates a collection of legs and has the following methods:

  • A default constructor that initializes this A-route to have the name "Unnamed A-route", to be designed by the artist "Unknown", to have a blank description, and to have 0 legs.
  • A constructor that initializes this A-route by parsing an A-route specification from a file. It accepts as its sole parameter a File. For example, the file might include this text:
    artist Chris Johnson
    name Helleau, Claire!
    description
    This is how I
    greet each day.
    enddescription
    leg
    name h
    closed false
    waypoint 44.801799 -91.491848
    waypoint 44.799473 -91.492579
    waypoint 44.800465 -91.492256
    waypoint 44.799940 -91.489048
    waypoint 44.798897 -91.489402
    endleg
    leg
    name base of i
    closed false
    waypoint 44.798638 -91.487889
    waypoint 44.799698 -91.487546
    waypoint 44.801051 -91.487363
    endleg
    leg
    name jot of i
    closed true
    waypoint 44.801744 -91.487277
    waypoint 44.802452 -91.487889
    waypoint 44.802916 -91.486591
    waypoint 44.802178 -91.486323
    endleg
    The artist and name commands follow the same whitespace rules as described above for a leg’s name command. A route’s description consists of the lines of text sandwiched between description and enddescription. The artist, name, description, and leg commands may appear in any order. However, when this route is run, the legs are passed through in their order of appearance. If any command is absent, the missing property takes on its default value.
  • Getters for the artist, name, and description, named according to convention (getProperty) and each returning the property as a String.
  • Setters for the artist, name, and description, named according to convention (setProperty) and each accepting a String as its sole parameter.
  • Method getLegCount that returns as an int the current number of legs on this A-route.
  • Method getLeg that accepts as its sole parameter the index of a leg within this route, of type int. It returns the Leg specified by the index.
  • Method toKml that accepts as its sole parameter a PrintWriter. It emits output in the following form to the PrintWriter:
    <Folder>
    <name>NAME</name>
    <description>DESCRIPTION</description>
    LEG0
    LEG1
    LEG2
    ...
    </Folder>
    
    The capitalized words are placeholders; they should be replaced with the actual properties of this A-route. The legs should be emitted in the format specified for Leg.

ArtistCatalog

Write class ArtistCatalog that represents a collection of A-routes organized by their artists. This class is meant to act as an array that is indexed not by an integer, but by an artist name. To retrieve all A-routes designed by artist Footographer, for example, we’d write catalog.get("Footographer").

We recommend you implement this class using two parallel lists: one for artist names and the other for the A-routes designed by the artist that appears in the corresponding slots of the artist names list. In future courses you will learn of implementations that make better use of memory and the CPU using a technique called hashing.

This class has the following methods:

  • A default constructor that initializes this catalog to have 0 artists and routes.
  • Method getArtists that returns the list of artists in the order that were added to the catalog. The list is returned as an ArrayList<Artist>.
  • Method has that accepts as its sole a parameter an artist of type String and returns a boolean. It returns true if and only if this artist is included in the catalog.
  • Method get that accepts as its sole a parameter an artist of type String. It returns the list of the artist’s A-routes, or null if the artist is not included in the catalog.
  • Method put that accepts as its sole a parameter an A-route of type Aroute. It appends the route to the list of routes designed by the new route’s artist.
  • Method toKml that accepts as its sole parameter a PrintWriter. It emits output in the following form to the PrintWriter:
    <?xml version="1.0" encoding="UTF-8"?>
    <kml xmlns="http://www.opengis.net/kml/2.2">
    <Document>
    <name>A-routes by Artist</name>
    <Style id="polylineStyle">
    <LineStyle>
    <color>7fff3333</color>
    <width>4</width>
    </LineStyle>
    </Style>
    <Folder>
    <name>ARTIST0</name>
    ARTIST0-AROUTE0
    ARTIST0-AROUTE1
    ARTIST0-AROUTE2
    </Folder>
    <Folder>
    <name>ARTIST1</name>
    ARTIST1-AROUTE0
    </Folder>
    ...
    </Document>
    </kml>
    
    The capitalized words are placeholders; they should be replaced with the actual properties of the artists and routes. The A-routes should be emitted in the format specified for Aroute.

Utilities

Write class Utilities with the following method:

  • Static method directoryToKml that accepts two parameters in the following order:
    • A directory of type File containing 0 or more A-route files
    • A KML file of type File to which to write an artist catalog
    This method creates an artist catalog and adds to it all A-route files found in the directory. It assumes the directory contains nothing but A-route files. Method listFiles in the File class is useful here, but its results are not guaranteed to be in any particular order—which leads to indeterminate results and complicates testing. Before adding the files to the catalog, it sorts the files by name using Arrays.sort. The catalog is written to the specified KML file, which can then be viewed in Google Earth or Google Maps.

Extra

For an extra credit participation point, create an A-route file for a run of your own design. Share your file and screenshot of it from Google Earth or Google Maps on Piazza under folder ec6 by the due date. The submission garnering the most votes will be honored in some way.

Submission

To check your work and submit it for grading:

  1. Run the SpecChecker by selecting hw6 SpecChecker from the run configurations dropdown in IntelliJ IDEA and clicking the run button.
  2. Fix problems until all tests pass.
  3. Commit and push your work to your repository.
  4. Verify on Gitlab that your submission uploaded successfully.

A passing SpecChecker does not guarantee you credit. Your grade is conditioned on a few things:

  • You must meet the requirements described above. The SpecChecker checks some of them, but not all.
  • You must not plagiarize. Write your own code. Talk about code with your classmates. Ask questions of your instructor or TA. Do not look at others’ code. Do not ask questions specific to your homework anywhere online but Piazza. Your instructor employs a vast repertoire of tools to sniff out academic dishonesty, including: drones, CS 1 moles, and a piece of software called MOSS that rigorously compares your code to every other submission. You don’t want to live in a world serviced by those who achieved their credentials by questionable means. For your future self, career, and family, do your own work.
  • Your code must be submitted correctly and on time. Machine and project issues are common—anticipate them. Commit early and often to Git. Extensions will not be granted. If you need more time to make things work, start earlier.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *