Manhattan

Source code in Manhattan.zip

  1. MainActivity.java: onCreate creates a ManhattanView and puts it on the screen.
  2. ManhattanView.java: a subclass of class View.
  3. R.java: creates the final int variables R.layout.activity_main, etc.
  4. activity_main.xml: ignored.
  5. strings.xml
  6. AndroidManifest.xml
  7. build.gradle (Module: app)

Coördinates

To get the latitude and longitude of each point on the shoreline, I wrote the plotter using the JavaScript Google Maps API Version 3.

Things to try

  1. onDraw would be faster if we created the Path once and for all in the constructor of the ManhattanView. The Path would be a field of the ManhattanView.

  2. Read the array of numbers from a string array in a resource file named arrays.xml. To create this file, go to the Android Studio project view and right-click on the folder Manhattan/res/values.
    New → Values resource file
    File name: arrays.xml
    OK
    Put the following content into the file. Each string contains one comma separating the longitude from the latitude.
    <?xml version="1.0" encoding="utf-8"?>
    
    <resources>
    	<string-array name="points">
    		<item>-73.971548f,	40.72921f</item>	<!-- East River at East 17th Street -->
    		<item>-73.974595f,	40.735519f</item>	<!-- 24 -->
    		<item>-73.971806f,	40.742998f</item>	<!-- 34 -->
    		<item>-73.96215f,	40.754767f</item>	<!-- 53 -->
    		<item>-73.954296f,	40.762146f</item>	<!-- 65 -->
    		<item>-73.946185f,	40.771474f</item>	<!-- 81 -->
    		<item>-73.942022f,	40.776154f</item>	<!-- 89 -->
    		<item>-73.942022f,	40.776154f</item>	<!-- 96 -->
    		<item>-73.93816f,	40.787008f</item>	<!-- 103 -->
    		<item>-73.929534f,	40.795326f</item>	<!-- 118 -->
    		<item>-73.929062f,	40.800946f</item>	<!-- 125 -->
    		<item>-73.934212f,	40.808775f</item>	<!-- Harlem River at 132nd Street -->
    		<item>-73.933868f,	40.817772f</item>	<!-- 143 -->
    		<item>-73.935113f,	40.83547f</item>	<!-- 163 -->
    		<item>-73.922195f,	40.855857f</item>	<!-- Dyckman Street -->
    		<item>-73.91078f,	40.869878f</item>	<!-- 218 -->
    		<item>-73.911767f,	40.873416f</item>	<!-- Broadway Bridge -->
    		<item>-73.922968f,	40.877018f</item>	<!-- Henry Hudson Parkway Bridge -->
    		<item>-73.926916f,	40.877082f</item>	<!-- Hudson River -->
    		<item>-73.933096f,	40.867379f</item>	<!-- Riverside Drive -->
    		<item>-73.943224f,	40.852417f</item>	<!-- Hudson River at West 181st Street -->
    		<item>-73.946786f,	40.850339f</item>	<!-- George Washington Bridge -->
    		<item>-73.946786f,	40.850339f</item>	<!-- 168 -->
    		<item>-73.95052f,	40.834626f</item>	<!-- 155 -->
    		<item>-73.955026f,	40.827417f</item>	<!-- 144 sewage treatment plant -->
    		<item>-73.956399f,	40.828034f</item>	<!-- 144 -->
    		<item>-73.959446f,	40.82365f</item>	<!-- 137 -->
    		<item>-73.957601f,	40.822676f</item>	<!-- 137 -->
    		<item>-73.994765f,	40.771669f</item>	<!-- 57 -->
    		<item>-73.995152f,	40.769524f</item>	<!-- 54 -->
    		<item>-73.999872f,	40.763316f</item>	<!-- 44 -->
    		<item>-74.001718f,	40.762276f</item>	<!-- 42 -->
    		<item>-74.007726f,	40.754052f</item>	<!-- 29 -->
    		<item>-74.009442f,	40.749825f</item>	<!-- 23 -->
    		<item>-74.00794f,	40.748362f</item>	<!-- 21 -->
    		<item>-74.009228f,	40.740754f</item>	<!-- Meatpacking District -->
    		<item>-74.010344f,	40.739258f</item>	<!-- Gansevoort Street -->
    		<item>-74.011545f,	40.726218f</item>	<!-- Holland Tunnel -->
    		<item>-74.013176f,	40.718315f</item>	<!-- Battery Park City -->
    		<item>-74.016609f,	40.718737f</item>	<!-- Battery Park City -->
    		<item>-74.019227f,	40.706539f</item>	<!-- South Cove -->
    		<item>-74.014893f,	40.70078f</item>	<!-- Battery Park -->
    		<item>-74.009314f,	40.701919f</item>	<!-- Heliport -->
    		<item>-73.997984f,	40.708523f</item>	<!-- north of Brooklyn Bridge -->
    		<item>-73.977985f,	40.710475f</item>	<!-- Corlears Hook Park -->
    		<item>-73.976011f,	40.712752f</item>	<!-- Grand Street -->
    		<item>-73.972964f,	40.720819f</item>	<!-- East 6th Street -->
    	</string-array>
    </resources>
    
    Copy the array of strings into the Path. You’ll have to rename the latitude variable because onDraw already contains a variable with this name.
    		Resources resources = getResources();
    		String[] points = resources.getStringArray(R.array.points);
    		Path path = new Path();
    
    		for (int i = 0; i < points.length; ++i) {
    			int comma = points[i].indexOf(",");
    
    			//everything before the comma
    			float longitude = Float.valueOf(points[i].substring(0, comma));
    
    			//everything after the comma
    			float latitude = Float.valueOf(points[i].substring(comma + 1));
    
    			if (i == 0) {
    				path.moveTo(longitude, latitude);
    			} else {
    				path.lineTo(longitude, latitude);
    			}
    		}
    

  3. Add Roosevelt Island, Governor’s Island, and/or Randall’s Island.

  4. Draw Central Park as a WHITE rectangle after you draw Manhattan.
    	Path park = new Path();
    	park.moveTo(-73.97305f, 40.764291f);	//Grand Army Plaza
    	park.lineTo(-73.981762f, 40.767997f);	//Columbus Circle
    	park.lineTo(-73.958116f, 40.800556f);	//Frederick Douglass Circle
    	park.lineTo(-73.949235f, 40.796848f);	//Frawley Circle
    
    	park.close();
    	canvas.drawPath(park, paint);
    
    What about the lakes in Central Park?

  5. Make Manhattan vertical by rotating it 28.9° counterclockwise. Insert the following immediately before the call to scale. Surprisingly, the rotation is specified in degrees, not radians.
    	canvas.rotate(-28.9f);	//degrees; negative for counterclockwise
    

  6. Make Manhattan wider. Insert the following immediately before the call to rotate.
    	canvas.scale(2.0f, 1.0f);
    

  7. Remove the transformations we just added in exercises 5 and 6. Print the CTM (Current Transformation Matrix) at the start of onDraw. You will have to import android.graphics.Matrix and android.util.Log. Direct the output of Log.d to the standard output as we did in Text. Why does the matrix have to be 3 × 3 when we’re drawing in only two dimensions?
    	//Canvas.getMatrix is deprecated, but View.getMatrix doesn't show the
    	//transformations we applied to the Canvas.
    	Matrix matrix = canvas.getMatrix();
    
    	float[] values = new float[9];	//Create an empty array.
    	matrix.getValues(values);	//Fill up the array.
    
    	Log.d("myTag", values[0] + "\t" + values[3] + "\t" + values[6]);
    	Log.d("myTag", values[1] + "\t" + values[4] + "\t" + values[7]);
    	Log.d("myTag", values[2] + "\t" + values[5] + "\t" + values[8]);
    
    1. At the start of onDraw, we got a perfect identity matrix:
      03-08 10:44:07.420    3656-3656/edu.nyu.scps.manhattan D/myTag: 1.0   0.0   1.0
      03-08 10:44:07.420    3656-3656/edu.nyu.scps.manhattan D/myTag: 0.0   1.0   0.0
      03-08 10:44:07.420    3656-3656/edu.nyu.scps.manhattan D/myTag: 0.0   0.0   1.0
      
    2. After the first canvas.translate on a Samsung Galaxy S5 in portrait orientation, the matrix is
      03-08 10:56:15.983    3760-3760/edu.nyu.scps.manhattan D/myTag:   1.0   0.0   0.0
      03-08 10:56:15.983    3760-3760/edu.nyu.scps.manhattan D/myTag:   0.0   1.0   0.0
      03-08 10:56:15.983    3760-3760/edu.nyu.scps.manhattan D/myTag: 540.0 838.0   1.0
      
      With the status and action bars visible, the ManhattanView is 1080 × 1677; see Japan. When we try to draw a point at (x, y), the point actually appears at screen coördinates (x′, y′), where x′ = 1x + 540
      y′ = 1y + 838
    3. After the canvas.scale, the matrix is
      03-08 11:09:24.745    3862-3862/edu.nyu.scps.manhattan D/myTag: 5078.688 0.0 0.0
      03-08 11:09:24.745    3862-3862/edu.nyu.scps.manhattan D/myTag: -0.0 -6708.0 -0.0
      03-08 11:09:24.749    3862-3862/edu.nyu.scps.manhattan D/myTag: 540.0 838.0 1.0
      
      When we try to draw a point at (x, y), the point actually appears at coördinates (x′, y′), where x′ = 5078.688x + 540
      y′ = –6708y + 838
    4. After the second canvas.translate, the matrix is
      03-08 11:13:56.166    3933-3933/edu.nyu.scps.manhattan D/myTag: 5078.688 0.0 0.0
      03-08 11:13:56.166    3933-3933/edu.nyu.scps.manhattan D/myTag: -0.0 -6708.0 -0.0
      03-08 11:13:56.166    3933-3933/edu.nyu.scps.manhattan D/myTag: 376185.13 274457.3 1.0
      
      When we try to draw a point at (x, y), the point actually appears at coördinates (x′, y′), where x′ = 5078.688x + 376185.13
      y′ = –6708y + 274457.3
      For example, the point at the East River and 17th Street has x = –73.971548 (the longitude) and y = 40.72921 (the latitude). The above formulæ yield x′ = 507 (the column) and y′ = 1246 (the row) when rounded to the nearest integer. This is a very modest pair of screen coördinates after all those huge numbers.