Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/formats/json/ExploreFormats.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ object ExploreFormats {
zoom: Int,
lat: Option[Float],
lng: Option[Float],
latUsingGsv: Option[Float],
lngUsingGsv: Option[Float],
computationMethod: Option[String]
)
case class LabelSubmission(
Expand Down Expand Up @@ -237,6 +239,8 @@ object ExploreFormats {
(JsPath \ "zoom").read[Int] and
(JsPath \ "lat").readNullable[Float] and
(JsPath \ "lng").readNullable[Float] and
(JsPath \ "lat_using_gsv").readNullable[Float] and
(JsPath \ "lng_using_gsv").readNullable[Float] and
(JsPath \ "computation_method").readNullable[String]
)(LabelPointSubmission.apply _)

Expand Down
17 changes: 10 additions & 7 deletions app/formats/json/LabelFormats.scala
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,13 @@ object LabelFormats {

def resumeLabelMetadatatoJson(label: ResumeLabelMetadata, allTags: Seq[Tag]): JsObject = {
Json.obj(
"labelId" -> label.labelData.labelId,
"labelType" -> label.labelType,
"panoId" -> label.labelData.gsvPanoramaId,
"panoLat" -> label.panoLat,
"panoLng" -> label.panoLng,
"originalPov" -> Json.obj(
"labelId" -> label.labelData.labelId,
"labelType" -> label.labelType,
"panoCaptureDate" -> label.panoCaptureDate,
"panoId" -> label.labelData.gsvPanoramaId,
"panoLat" -> label.panoLat,
"panoLng" -> label.panoLng,
"originalPov" -> Json.obj(
"heading" -> label.pointData.heading,
"pitch" -> label.pointData.pitch,
"zoom" -> label.pointData.zoom
Expand All @@ -216,7 +217,9 @@ object LabelFormats {
"auditTaskId" -> label.labelData.auditTaskId,
"missionId" -> label.labelData.missionId,
"labelLat" -> label.pointData.lat,
"labelLng" -> label.pointData.lng
"labelLng" -> label.pointData.lng,
"latUsingGsv" -> label.pointData.geomUsingGsv.map(_.getY),
"lngUsingGsv" -> label.pointData.geomUsingGsv.map(_.getX)
)
}
}
4 changes: 3 additions & 1 deletion app/models/label/LabelPointTable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ case class LabelPoint(
lat: Option[Float],
lng: Option[Float],
geom: Option[Point],
geomUsingGsv: Option[Point],
computationMethod: Option[String]
)

Expand All @@ -37,9 +38,10 @@ class LabelPointTableDef(tag: slick.lifted.Tag) extends Table[LabelPoint](tag, "
def lat: Rep[Option[Float]] = column[Option[Float]]("lat")
def lng: Rep[Option[Float]] = column[Option[Float]]("lng")
def geom: Rep[Option[Point]] = column[Option[Point]]("geom")
def geomUsingGsv: Rep[Option[Point]] = column[Option[Point]]("geom_using_gsv")
def computationMethod: Rep[Option[String]] = column[Option[String]]("computation_method")

def * = (labelPointId, labelId, panoX, panoY, canvasX, canvasY, heading, pitch, zoom, lat, lng, geom,
def * = (labelPointId, labelId, panoX, panoY, canvasX, canvasY, heading, pitch, zoom, lat, lng, geom, geomUsingGsv,
computationMethod) <> ((LabelPoint.apply _).tupled, LabelPoint.unapply)

// def label: ForeignKeyQuery[LabelTable, Label] =
Expand Down
6 changes: 4 additions & 2 deletions app/models/label/LabelTable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ case class ResumeLabelMetadata(
labelData: Label,
labelType: String,
pointData: LabelPoint,
panoCaptureDate: String,
panoLat: Option[Float],
panoLng: Option[Float],
cameraHeading: Option[Float],
Expand Down Expand Up @@ -1218,8 +1219,9 @@ class LabelTable @Inject() (protected val dbConfigProvider: DatabaseConfigProvid
_gsvData <- gsvData if _label.gsvPanoramaId === _gsvData.gsvPanoramaId
if _mission.regionId === regionId && _mission.userId === userId
if _labelPoint.lat.isDefined && _labelPoint.lng.isDefined
} yield (_label, _labelType.labelType, _labelPoint, _gsvData.lat, _gsvData.lng, _gsvData.cameraHeading,
_gsvData.cameraPitch, _gsvData.width, _gsvData.height)).result.map(_.map(ResumeLabelMetadata.tupled))
} yield (_label, _labelType.labelType, _labelPoint, _gsvData.captureDate, _gsvData.lat, _gsvData.lng,
_gsvData.cameraHeading, _gsvData.cameraPitch, _gsvData.width, _gsvData.height)).result
.map(_.map(ResumeLabelMetadata.tupled))
}

/**
Expand Down
6 changes: 5 additions & 1 deletion app/service/ExploreService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,10 @@ class ExploreServiceImpl @Inject() (
_lat <- point.lat
_lng <- point.lng
} yield gf.createPoint(new Coordinate(_lng.toDouble, _lat.toDouble))
val pointGeomUsingGsv: Option[Point] = for {
_lat <- point.latUsingGsv
_lng <- point.lngUsingGsv
} yield gf.createPoint(new Coordinate(_lng.toDouble, _lat.toDouble))

for {
// Use label's lat/lng to determine street_edge_id. If lat/lng isn't defined, use audit_task's as backup.
Expand Down Expand Up @@ -406,7 +410,7 @@ class ExploreServiceImpl @Inject() (
// Add an entry to the label_point table.
_ <- labelPointTable.insert(
LabelPoint(0, newLabelId, point.panoX, point.panoY, point.canvasX, point.canvasY, point.heading, point.pitch,
point.zoom, point.lat, point.lng, pointGeom, point.computationMethod)
point.zoom, point.lat, point.lng, pointGeom, pointGeomUsingGsv, point.computationMethod)
)
} yield {
(newLabelId, label.temporaryLabelId, timeCreated)
Expand Down
7 changes: 7 additions & 0 deletions conf/evolutions/default/278.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# --- !Ups
ALTER TABLE label_point
ADD COLUMN geom_using_gsv geometry(Point, 4326);

# --- !Downs
ALTER TABLE label_point
DROP COLUMN geom_using_gsv;
9 changes: 8 additions & 1 deletion public/javascripts/SVLabel/src/SVLabel/Main.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,13 @@ function Main (params) {
});
logPageFocus();

// Sets up Google Maps OverlayView, which is used to tie labels to a lat/lng, showing them on nearby panos.
svl.overlay = new google.maps.OverlayView();
svl.overlay.onAdd = function () {};
svl.overlay.draw = function () {};
svl.overlay.onRemove = function () {};
svl.overlay.setMap(svl.panorama);

// Modals
var modalMissionCompleteMap = new ModalMissionCompleteMap(svl.ui.modalMissionComplete, params.mapboxApiKey);
var modalMissionCompleteProgressBar = new ModalMissionCompleteProgressBar(svl.ui.modalMissionComplete);
Expand Down Expand Up @@ -320,7 +327,7 @@ function Main (params) {

svl.labelContainer.fetchLabelsToResumeMission(neighborhood.getRegionId(), function (result) {
svl.statusFieldNeighborhood.setLabelCount(svl.labelContainer.countLabels());
svl.canvas.setOnlyLabelsOnPanoAsVisible(svl.map.getPanoId());
svl.canvas.setOnlyLabelsInViewAsVisible(svl.map.getPanoId());

// Count the labels of each label type to initialize the current mission label counts.
var counter = {'CurbRamp': 0, 'NoCurbRamp': 0, 'Obstacle': 0, 'SurfaceProblem': 0, 'NoSidewalk': 0, 'Other': 0};
Expand Down
8 changes: 4 additions & 4 deletions public/javascripts/SVLabel/src/SVLabel/canvas/Canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ function Canvas(ribbon) {
if (!status.disableLabeling && currTime - mouseStatus.prevMouseUpTime > 300) {
createLabel(mouseStatus.leftUpX, mouseStatus.leftUpY);
clear();
setOnlyLabelsOnPanoAsVisible(svl.map.getPanoId());
setOnlyLabelsInViewAsVisible(svl.map.getPanoId());
render();
}

Expand Down Expand Up @@ -330,10 +330,10 @@ function Canvas(ribbon) {
/**
* Sets labels on the given pano as visible, all others as hidden.
*/
function setOnlyLabelsOnPanoAsVisible(panoramaId) {
function setOnlyLabelsInViewAsVisible(panoramaId) {
var labels = svl.labelContainer.getCanvasLabels();
for (var i = 0; i < labels.length; i += 1) {
if (labels[i].getPanoId() === panoramaId && !labels[i].isDeleted()) {
if (!labels[i].isDeleted()) {
labels[i].setVisibility('visible');
} else {
labels[i].setVisibility('hidden');
Expand Down Expand Up @@ -376,7 +376,7 @@ function Canvas(ribbon) {
self.setStatus = setStatus;
self.showLabelHoverInfo = showLabelHoverInfo;
self.setVisibility = setVisibility;
self.setOnlyLabelsOnPanoAsVisible = setOnlyLabelsOnPanoAsVisible;
self.setOnlyLabelsInViewAsVisible = setOnlyLabelsInViewAsVisible;
self.unlockDisableLabelDelete = unlockDisableLabelDelete;
self.saveGSVScreenshot = saveGSVScreenshot;

Expand Down
12 changes: 11 additions & 1 deletion public/javascripts/SVLabel/src/SVLabel/data/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ function Form (labelContainer, missionModel, missionContainer, navigationModel,
var tempLabelId = label.getProperty('temporaryLabelId');
var auditTaskId = label.getProperty('auditTaskId');

var labelLatUsingGsv = label.getProperty('latUsingGsv');
var labelLngUsingGsv = label.getProperty('lngUsingGsv');

// If this label is a new label, get the timestamp of its creation from the corresponding interaction.
var associatedInteraction = data.interactions.find(interaction =>
interaction.action === 'LabelingCanvas_FinishLabeling'
Expand Down Expand Up @@ -127,7 +130,9 @@ function Form (labelContainer, missionModel, missionContainer, navigationModel,
pitch: prop.originalPov.pitch,
zoom : prop.originalPov.zoom,
lat : null,
lng : null
lng : null,
lat_using_gsv : null,
lng_using_gsv : null
}
};

Expand All @@ -137,6 +142,11 @@ function Form (labelContainer, missionModel, missionContainer, navigationModel,
temp.label_point.computation_method = labelLatLng.latLngComputationMethod;
}

if (labelLatUsingGsv && labelLngUsingGsv) {
temp.label_point.lat_using_gsv = labelLatUsingGsv;
temp.label_point.lng_using_gsv = labelLngUsingGsv;
}

data.labels.push(temp)
}

Expand Down
64 changes: 60 additions & 4 deletions public/javascripts/SVLabel/src/SVLabel/label/Label.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,13 @@ function Label(params) {
povOfLabelIfCentered: undefined,
labelLat: undefined,
labelLng: undefined,
latUsingGsv: undefined,
lngUsingGsv: undefined,
latLngComputationMethod: undefined,
panoId: undefined,
panoLat: undefined,
panoLng: undefined,
panoCaptureDate: undefined,
cameraHeading: undefined,
panoWidth: undefined,
panoHeight: undefined,
Expand Down Expand Up @@ -94,6 +97,7 @@ function Label(params) {
properties.panoXY = util.panomarker.calculatePanoXYFromPov(
properties.povOfLabelIfCentered, properties.cameraHeading, properties.panoWidth, properties.panoHeight
);
properties.panoCaptureDate = panoData.imageDate;
}

// Create the marker on the minimap.
Expand Down Expand Up @@ -203,9 +207,36 @@ function Label(params) {

// Update the coordinates of the label on the canvas.
if (svl.map.getPovChangeStatus()) {
properties.currCanvasXY = util.panomarker.getCanvasCoordinate(
properties.povOfLabelIfCentered, pov, util.EXPLORE_CANVAS_WIDTH, util.EXPLORE_CANVAS_HEIGHT, svl.LABEL_ICON_RADIUS
);
if (svl.map.getPanoId() === properties.panoId) {
properties.currCanvasXY = util.panomarker.getCanvasCoordinate(
properties.povOfLabelIfCentered, pov, util.EXPLORE_CANVAS_WIDTH, util.EXPLORE_CANVAS_HEIGHT, svl.LABEL_ICON_RADIUS
);
} else {
// If the pano has changed, we need to recalculate the label's canvas coordinates. Using the label's
// lat/lng. Ideally use the one calculated from GSV, but use our own fallback lat/lng if not avail.
let latLng = null;
if (getProperty('latUsingGsv') && getProperty('lngUsingGsv')) {
latLng = new google.maps.LatLng(getProperty('latUsingGsv'), getProperty('lngUsingGsv'));
} else if (getProperty('labelLat') && getProperty('labelLng')) {
// Fallback to regression-calculated lat/lng if GSV lat/lng is not available.
latLng = this.toLatLng();
}

// Calculate new canvas coordinates from the label's lat/lng.
const projection = svl.overlay.getProjection();
const canvasXY = projection.fromLatLngToContainerPixel(latLng);
if(canvasXY != null) {
properties.currCanvasXY = {
x: canvasXY.x,
y: canvasXY.y
};
} else {
properties.currCanvasXY = {
x: null,
y: null
};
}
}
}

// Draw the label icon if it's in the visible part of the pano.
Expand Down Expand Up @@ -353,7 +384,32 @@ function Label(params) {
*/
function toLatLng() {
if (!properties.labelLat) {
// Estimate the latlng point from the camera position and the heading when point cloud data isn't available.
// Estimating lat/lng from GSV canvas coordinates.
let gsvEstimatedLatLng = null;
if (properties.currCanvasXY.x) {
try {
const projection = svl.overlay.getProjection();

const latLng = projection.fromContainerPixelToLatLng({
x: properties.currCanvasXY.x,
y: properties.currCanvasXY.y
});

gsvEstimatedLatLng = {lat: latLng.lat(), lng: latLng.lng()}
} catch (e) {
console.error('Error estimating GSV lat/lng for label:', e);
}
}
if (gsvEstimatedLatLng) {
const gsvLatLng = {
lat: gsvEstimatedLatLng.lat,
lng: gsvEstimatedLatLng.lng,
};
setProperty('latUsingGsv', gsvLatLng.lat);
setProperty('lngUsingGsv', gsvLatLng.lng);
}

// Estimate the latlng point from the camera position and the heading.
var panoLat = getProperty("panoLat");
var panoLng = getProperty("panoLng");
var panoHeading = getProperty("originalPov").heading;
Expand Down
26 changes: 23 additions & 3 deletions public/javascripts/SVLabel/src/SVLabel/label/LabelContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,31 @@ function LabelContainer ($, nextTemporaryLabelId) {
}

/**
* Returns labels for the current pano ID.
* Returns labels for the current view.
*/
this.getCanvasLabels = function () {
let panoId = svl.map.getPanoId();
return allLabels[panoId] ? allLabels[panoId] : [];
const panoId = svl.map.getPanoId();
const panoLatLng = svl.map.getPosition();
// During the transition to the next panorama, the new panorama might not be in the container.
// Therefore, we must check if the panorama exists before proceeding.
if (svl.panoramaContainer.getPanorama(panoId) === null) {
return [];
}
const panoDate = svl.panoramaContainer.getPanorama(panoId).data().imageDate;
return this.getAllLabels().filter(function (label) {
// Is the label in the current pano?
const presentInPano = label.getPanoId() === svl.map.getPanoId();
// Calculate distance between label and current pano.
const labelLatLng = label.toLatLng();
const distance = turf.distance(turf.point([labelLatLng.lng, labelLatLng.lat]),
turf.point([panoLatLng.lng, panoLatLng.lat]), { units: "meters" });
// Check if date of label and pano match.
const dateMatches = panoDate === label.getProperty('panoCaptureDate');

// We may want to do further testing to determine the optimal distance threshold.
// For now, we use 25m as a threshold.
return presentInPano || (distance < 25 && dateMatches);
});
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ function MapService (canvas, neighborhoodModel, uiMap, params) {

povChange["status"] = true;
_canvas.clear();
_canvas.setOnlyLabelsOnPanoAsVisible(panoId);
_canvas.setOnlyLabelsInViewAsVisible(panoId);
_canvas.render();
povChange["status"] = false;

Expand Down Expand Up @@ -1115,7 +1115,7 @@ function MapService (canvas, neighborhoodModel, uiMap, params) {
function updateCanvas() {
_canvas.clear();
if (status.currPanoId !== getPanoId()) {
_canvas.setOnlyLabelsOnPanoAsVisible(getPanoId());
_canvas.setOnlyLabelsInViewAsVisible(getPanoId());
}
status.currPanoId = getPanoId();
_canvas.render();
Expand Down