Skip to content

Commit

Permalink
More admin interface improvements. #15.
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt Conway committed Aug 29, 2012
1 parent 620046c commit 24f1e57
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 7 deletions.
100 changes: 98 additions & 2 deletions app/controllers/Admin.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package controllers;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.math.BigInteger;

import javax.persistence.Query;

import com.vividsolutions.jts.geom.Geometry;

import play.db.jpa.JPA;

import models.MetroArea;
import models.NtdAgency;
import models.ReviewType;

public class Admin extends Mapper {
/**
Expand All @@ -24,11 +30,101 @@ public static void index () {

q = JPA.em().createNativeQuery("SELECT count(*) FROM NtdAgency WHERE review = 'AGENCY_MULTIPLE_AREAS'");
results = q.getResultList();
int agenciesNoMetro = results.get(0).intValue();
int agenciesMultiAreas = results.get(0).intValue();

render(feedsNoAgency, agenciesNoMetro);
render(feedsNoAgency, agenciesMultiAreas);
}

private static class MetroAreaWithGeom {
private String name;
// in GeoJSON format
private String geom;
}

/**
* Show agencies which match multiple areas
*/
public static void agenciesMultiAreas () {
List<NtdAgency> agenciesMultiAreas =
NtdAgency.find("byReview", ReviewType.AGENCY_MULTIPLE_AREAS).fetch();

// This maps an agency ID to a metro area
Map<Long, List<MetroAreaWithGeom>> metros = new HashMap<Long, List<MetroAreaWithGeom>>();

MetroAreaWithGeom metro;
for (NtdAgency agency : agenciesMultiAreas) {
// find metro area(s)
Geometry agencyGeom = agency.getGeom();
String query = "SELECT m.name, ST_AsGeoJSON(the_geom) FROM MetroArea m WHERE " +
"ST_DWithin(m.the_geom, transform(ST_GeomFromText(?, ?), ST_SRID(m.the_geom)), 0.04)";;
Query ids = JPA.em().createNativeQuery(query);
ids.setParameter(1, agencyGeom.toText());
ids.setParameter(2, agencyGeom.getSRID());
List<Object[]> metrosTemp = ids.getResultList();

for (Object[] result : metrosTemp) {
metro = new MetroAreaWithGeom();
metro.name = (String) result[0];
metro.geom = (String) result[1];

if (!metros.containsKey(agency.id))
metros.put(agency.id, new ArrayList<MetroAreaWithGeom>());

metros.get(agency.id).add(metro);
}
}

render(agenciesMultiAreas, metros);
}

/**
* This just disables an agency and clears the review flag.
*/
public static void disableAgency(NtdAgency agency) {
agency.disabled = true;
agency.review = null;
agency.save();
agenciesMultiAreas();
}

/**
* This merges all the areas the agency could be considered part of.
*/
public static void mergeAllAreas (NtdAgency agency) {
try {
agency.mergeAllAreas();
} catch (NullPointerException e) {
flash("error", "invalid geometry for agency");
agenciesMultiAreas();
return;
}

agency.review = null;
agency.save();
agenciesMultiAreas();
}

/**
* For an agency that overlaps multiple metro areas, this makes the agency a member of each of them with no
* merging. This should be used, for example, when there are multiple distinct metro areas that have a single agency that
* serves all of them (for instance, NJ Transit in NYC).
*/
public static void splitToAreas (NtdAgency agency) {
try {
agency.splitToAreas();
} catch (NullPointerException e) {
flash("error", "agency has no valid geometry");
agenciesMultiAreas();
return;
}

agency.review = null;
agency.save();

// redirect back
// http://stackoverflow.com/questions/4283256
agenciesMultiAreas();
}

/**
* Actually perform the split for a given metro
Expand Down
88 changes: 88 additions & 0 deletions app/models/NtdAgency.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

import javax.persistence.*;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.operation.overlay.OverlayOp;

import java.math.BigInteger;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import play.db.jpa.*;
import play.data.validation.*;
import utils.GeometryUtils;

@Entity
public class NtdAgency extends Model {
Expand Down Expand Up @@ -73,6 +79,11 @@ public List<MetroArea> getMetroAreas () {
@ManyToMany(cascade=CascadeType.PERSIST)
public Set<GtfsFeed> feeds;

/**
* Is this agency disabled?
*/
public boolean disabled;

/**
* Convert to a human-readable string. This is exposed in the admin interface, so it should be
* correct.
Expand Down Expand Up @@ -100,6 +111,7 @@ public NtdAgency (String name, String url, String ntdId, int population,
this.passengerMiles = passengerMiles;
this.source = AgencySource.NTD;
this.note = null;
this.disabled = false;
feeds = new HashSet<GtfsFeed>();
}

Expand All @@ -115,7 +127,83 @@ public NtdAgency(GtfsFeed feed) {
this.population = 0;
this.ridership = 0;
this.passengerMiles = 0;
this.disabled = feed.disabled;
this.source = AgencySource.GTFS;
feeds = new HashSet<GtfsFeed>();
}

public Geometry getGeom() {
Geometry out = null;
Integer srid = null;

for (GtfsFeed feed : feeds) {
// ignore feeds that did not parse as they will have null geoms
if (feed.status != FeedParseStatus.SUCCESSFUL)
continue;

if (srid == null)
srid = feed.the_geom.getSRID();

if (out == null)
out = feed.the_geom;
else
out = OverlayOp.overlayOp(out, feed.the_geom, OverlayOp.UNION);
}

// re-set SRID, it gets lost
if (out != null)
out.setSRID(srid);

return out;
}

/**
* Make this agency a member of every metro it overlaps, without merging anything.
*/
public void splitToAreas() {
Geometry agencyGeom = this.getGeom();

String query = "SELECT m.id FROM MetroArea m WHERE " +
"ST_DWithin(m.the_geom, transform(ST_GeomFromText(?, ?), ST_SRID(m.the_geom)), 0.04)";;
Query ids = JPA.em().createNativeQuery(query);
ids.setParameter(1, agencyGeom.toText());
ids.setParameter(2, agencyGeom.getSRID());
List<BigInteger> metrosTemp = ids.getResultList();

MetroArea metro;
for (BigInteger metroId : metrosTemp) {
metro = MetroArea.findById(metroId.longValue());
metro.agencies.add(this);
metro.save();
}
}

/**
* Merge all the areas this agency is potentially a part of. Beware this will create huge agencies if
* it is applied to (a) something like Amtrak or Greyhound or (b) an agency with a few misplaced stops
* far away in other metros; since geoms are convex-hulled, they will cross lots of areas.
*/
public void mergeAllAreas() {
Geometry agencyGeom = this.getGeom();

String query = "SELECT m.id FROM MetroArea m WHERE " +
"ST_DWithin(m.the_geom, transform(ST_GeomFromText(?, ?), ST_SRID(m.the_geom)), 0.04)";;
Query ids = JPA.em().createNativeQuery(query);
ids.setParameter(1, agencyGeom.toText());
ids.setParameter(2, agencyGeom.getSRID());
List<BigInteger> metrosTemp = ids.getResultList();

MetroArea metro;
MetroArea first = MetroArea.findById(metrosTemp.get(0).longValue());
metrosTemp.remove(0);

for (BigInteger metroId : metrosTemp) {
metro = MetroArea.findById(metroId.longValue());
first.mergeAreas(metro);
metro.delete();
}

first.agencies.add(this);
first.save();
}
}
6 changes: 3 additions & 3 deletions app/views/Admin/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ <h2>Items requiring review</h2>

<ul>
<li><a href="feedsNoAgencies">Feeds with no agencies
<span class="label label-info">${feedsNoAgency}</span></a></li>
<li><a href="agenciesNoMetros">Agencies with no metro areas
<span class="label label-info">${agenciesNoMetro}</span></a></li>
<span class="badge badge-info">${feedsNoAgency}</span></a></li>
<li><a href="agenciesMultiAreas">Agencies matching multiple metro areas
<span class="badge badge-info">${agenciesMultiAreas}</span></a></li>
</ul>


Expand Down
5 changes: 3 additions & 2 deletions app/views/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="#">Transit Data Dashboard</a>
<h4>Administration</h4>
<a class="brand" href="#">Transit Data Dashboard</a>
<h4>Administration</h4>
</div>
</div>
</div>
<div class="container">
Expand Down

0 comments on commit 24f1e57

Please sign in to comment.