Skip to content

Commit

Permalink
Adding new endpoints for the tiler to adapt the image size based on t…
Browse files Browse the repository at this point in the history
…he zoom level. Fixing the building functionality.
  • Loading branch information
Costantinos committed Jun 8, 2018
1 parent 74b98f8 commit bbc5a7b
Show file tree
Hide file tree
Showing 32 changed files with 802 additions and 173 deletions.
14 changes: 9 additions & 5 deletions server/anyplace_tiler/anyplace-tiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ def convertPaddedImage( filename, newW, newH, outputName ):


def resizeImage( srcImage, zoomOriginal, zoomCurrent, destImage ):
resRatio = 50#100.0 / (2 ** (zoomOriginal-zoomCurrent) )
rasRatio=100
if(zoomOriginal!=zoomCurrent):
resRatio = 100.0 / (2 ** (zoomOriginal-zoomCurrent) )
print(resRatio)
dim = subprocess.Popen(["convert", srcImage, "-resize", ('%d%%'%(resRatio)), destImage ], stdout=subprocess.PIPE).communicate()[0]

#####################################################################################
Expand Down Expand Up @@ -174,7 +177,7 @@ def fixTileStructure( fixTileStructureScript, ImageFileName ):
def main( argv ):
print( argv )

if(7 != len(sys.argv)):
if(8 != len(sys.argv)):
print(usage())
sys.exit(1)

Expand All @@ -184,6 +187,7 @@ def main( argv ):
OriginalZoom = int(sys.argv[4])
ToZoom = int(sys.argv[5])
ImageFileName = sys.argv[6]
UploadZoom = int(sys.argv[7])
ImageDirName = os.path.dirname(os.path.realpath(ImageFileName))

fixTileStructureScript = str(ScriptsDir + '/fix-tile-structure.sh')
Expand All @@ -195,13 +199,13 @@ def main( argv ):

# we will run the procedure for every zoom level in range [OriginalZoom..ToZoom]
for currentZoom in range( OriginalZoom, (ToZoom-1), -1 ):

currentImage=ImageFileName
# call the command to resize the image according to the zoom level
if( currentZoom == OriginalZoom ):
if( currentZoom == UploadZoom ):
currentImage=ImageFileName
else:
newName=(('%s-z%d.png') % (CURRENT_ZOOM_IMAGE_NAME, currentZoom))
resizeImage(currentImage, OriginalZoom, currentZoom, newName)
resizeImage(currentImage, UploadZoom, currentZoom, newName)
currentImage = newName

# get the Image top left world coords
Expand Down
7 changes: 4 additions & 3 deletions server/anyplace_tiler/start-anyplace-tiler.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ check_requirements(){

##################### MAIN

[[ "$#" != "4" ]] && usage
[[ "$#" != "5" ]] && usage

[[ "$4" != "-ENLOG" && "$4" != "-DISLOG" ]] && usage

Expand Down Expand Up @@ -96,16 +96,17 @@ echo "Image: $imagePath"

ImageLatitude="$2"
ImageLongitude="$3"
ZoomOriginal=21
ZoomOriginal=22
ZoomDestination=19
ImageFileName="$imagePath"
UploadZoom="$5"


echo
echo ":: Starting anyplace-tiler ..."
anyTiler="$scriptsDir/anyplace-tiler.py"

python "$anyTiler" "$scriptsDir" "$ImageLatitude" "$ImageLongitude" "$ZoomOriginal" "$ZoomDestination" "$ImageFileName"
python "$anyTiler" "$scriptsDir" "$ImageLatitude" "$ImageLongitude" "$ZoomOriginal" "$ZoomDestination" "$ImageFileName" "$UploadZoom"
check_for_errors

echo
Expand Down
78 changes: 71 additions & 7 deletions server/app/controllers/AnyplaceMapping.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2419,11 +2419,6 @@ object AnyplaceMapping extends play.api.mvc.Controller {

def serveFloorPlanTilesStatic(buid: String, floor_number: String, path: String) = Action {
def inner(): Result = {
LPLogger.info("AnyplaceMapping::serveFloorPlanTilesStatic(): " + buid +
":" +
floor_number +
":" +
path)
if (path == null || buid == null || floor_number == null ||
path.trim().isEmpty ||
buid.trim().isEmpty ||
Expand All @@ -2432,10 +2427,10 @@ object AnyplaceMapping extends play.api.mvc.Controller {
filePath = if (path == AnyPlaceTilerHelper.FLOOR_TILES_ZIP_NAME) AnyPlaceTilerHelper.getFloorTilesZipFor(buid,
floor_number) else AnyPlaceTilerHelper.getFloorTilesDirFor(buid, floor_number) +
path
LPLogger.info("static requested: " + filePath)
try {
val file = new File(filePath)
if (!file.exists() || !file.canRead()) return AnyResponseHelper.not_found("File requested not found")
//send ok message to tiler
if (!file.exists() || !file.canRead()) return AnyResponseHelper.ok("File requested not found")
Ok.sendFile(file)
} catch {
case e: FileNotFoundException => return AnyResponseHelper.internal_server_error("Could not read floor plan.")
Expand Down Expand Up @@ -2627,6 +2622,75 @@ object AnyplaceMapping extends play.api.mvc.Controller {
inner(request)
}

def floorPlanUploadWithZoom() = Action {
implicit request =>

def inner(request: Request[AnyContent]): Result = {
val anyReq = new OAuth2Request(request)
val body = anyReq.getMultipartFormData()
if (body == null) return AnyResponseHelper.bad_request("Invalid request type - Not Multipart!")
var floorplan = body.file("floorplan").get
if (floorplan == null) return AnyResponseHelper.bad_request("Cannot find the floor plan file in your request!")
val urlenc = body.asFormUrlEncoded
val json_str = urlenc.get("json").get(0)
if (json_str == null) return AnyResponseHelper.bad_request("Cannot find json in the request!")
var json: JsonObject = null
try {
json = JsonObject.fromJson(json_str)
} catch {
case e: IOException => return AnyResponseHelper.bad_request("Cannot parse json in the request!")
}
LPLogger.info("Floorplan Request[json]: " + json.toString)
LPLogger.info("Floorplan Request[floorplan]: " + floorplan.filename)
val requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid", "floor_number", "bottom_left_lat",
"bottom_left_lng", "top_right_lat", "top_right_lng","zoom")
if (!requiredMissing.isEmpty) return AnyResponseHelper.requiredFieldsMissing(requiredMissing)
val buid = json.getString("buid")
val zoom = json.getString("zoom")
val zoom_number = json.getString("zoom").toInt
if (zoom_number<20)
return AnyResponseHelper.bad_request("You have provided zoom level "+zoom+". You have to zoom at least to level 20 to upload the floorplan.")

val floor_number = json.getString("floor_number")
val bottom_left_lat = json.getString("bottom_left_lat")
val bottom_left_lng = json.getString("bottom_left_lng")
val top_right_lat = json.getString("top_right_lat")
val top_right_lng = json.getString("top_right_lng")
val fuid = Floor.getId(buid, floor_number)
try {
val stored_floor = ProxyDataSource.getIDatasource.getFromKeyAsJson(fuid)
if (stored_floor == null) return AnyResponseHelper.bad_request("Floor does not exist or could not be retrieved!")
stored_floor.put("zoom", zoom)
stored_floor.put("bottom_left_lat", bottom_left_lat)
stored_floor.put("bottom_left_lng", bottom_left_lng)
stored_floor.put("top_right_lat", top_right_lat)
stored_floor.put("top_right_lng", top_right_lng)
if (!ProxyDataSource.getIDatasource.replaceJsonDocument(fuid, 0, stored_floor.toString))
return AnyResponseHelper.bad_request("Floor plan could not be updated in the database!")
} catch {
case e: DatasourceException => return AnyResponseHelper.internal_server_error("Error while reading from our backend service!")
}
var floor_file: File = null
try {
floor_file = AnyPlaceTilerHelper.storeFloorPlanToServer(buid, floor_number, floorplan.ref.file)
} catch {
case e: AnyPlaceException => return AnyResponseHelper.bad_request("Cannot save floor plan on the server!")
}
val top_left_lat = top_right_lat
val top_left_lng = bottom_left_lng
try {
AnyPlaceTilerHelper.tileImageWithZoom(floor_file, top_left_lat, top_left_lng,zoom)
} catch {
case e: AnyPlaceException => return AnyResponseHelper.bad_request("Could not create floor plan tiles on the server!")
}
LPLogger.info("Successfully tiled [" + floor_file.toString + "]")
return AnyResponseHelper.ok("Successfully updated floor plan!")
}

inner(request)
}


def addAccount() = Action {
implicit request =>

Expand Down
127 changes: 126 additions & 1 deletion server/app/controllers/AnyplacePosition.scala
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,131 @@ object AnyplacePosition extends play.api.mvc.Controller {
}


/**
* Returns a link to the radio map that needs to be downloaded according to the specified buid and floor
*
* @return a link to the radio_map file
*/
def radioDownloadByBuildingFloorall() = Action {
implicit request =>
def inner(request: Request[AnyContent]): Result = {

val anyReq = new OAuth2Request(request)
if (!anyReq.assertJsonBody()) {
return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON)
}
val json = anyReq.getJsonBody
LPLogger.info("AnyplacePosition::radioDownloadFloor(): " + json.toString)
val requiredMissing = JsonUtils.requirePropertiesInJson(json, "floor", "buid")
if (!requiredMissing.isEmpty) {
return AnyResponseHelper.requiredFieldsMissing(requiredMissing)
}
val floor_numbers = (json \ "floor").as[String]
val buid = (json \ "buid").as[String]

val floors = floor_numbers.split(" ")

val radiomap_mean_filename = JsonArray.empty()

val rss_log_files = JsonArray.empty()

for (floor_number <- floors) {
val rmapDir = new File("radiomaps_frozen" + AnyplaceServerAPI.URL_SEPARATOR + buid + AnyplaceServerAPI.URL_SEPARATOR +
floor_number)
val radiomapFile = new File("radiomaps_frozen" + AnyplaceServerAPI.URL_SEPARATOR + buid + AnyplaceServerAPI.URL_SEPARATOR +
floor_number +
AnyplaceServerAPI.URL_SEPARATOR +
"indoor-radiomap.txt")
val meanFile = new File("radiomaps_frozen" + AnyplaceServerAPI.URL_SEPARATOR + buid + AnyplaceServerAPI.URL_SEPARATOR +
floor_number +
AnyplaceServerAPI.URL_SEPARATOR +
"indoor-radiomap-mean.txt")
if (rmapDir.exists() && radiomapFile.exists() && meanFile.exists()) {
try {
val folder = rmapDir.toString
val radiomap_filename = new File(folder + AnyplaceServerAPI.URL_SEPARATOR + "indoor-radiomap.txt")
.getAbsolutePath
var radiomap_mean_filename = radiomap_filename.replace(".txt", "-mean.txt")
var radiomap_rbf_weights_filename = radiomap_filename.replace(".txt", "-weights.txt")
var radiomap_parameters_filename = radiomap_filename.replace(".txt", "-parameters.txt")
val api = AnyplaceServerAPI.SERVER_API_ROOT
var pos = radiomap_mean_filename.indexOf("radiomaps_frozen")
radiomap_mean_filename = api + radiomap_mean_filename.substring(pos)
pos = radiomap_rbf_weights_filename.indexOf("radiomaps_frozen")
radiomap_rbf_weights_filename = api + radiomap_rbf_weights_filename.substring(pos)
pos = radiomap_parameters_filename.indexOf("radiomaps_frozen")
radiomap_parameters_filename = api + radiomap_parameters_filename.substring(pos)
} catch {
case e: Exception => return AnyResponseHelper.internal_server_error("Error serving radiomap : " + e.getMessage)
}
}
if (!rmapDir.exists())
if (!rmapDir.mkdirs()) {
return AnyResponseHelper.internal_server_error("Error while creating Radio Map on-the-fly!")
}
val radio = new File(rmapDir.getAbsolutePath + AnyplaceServerAPI.URL_SEPARATOR + "rss-log")
var fout: FileOutputStream = null
try {
fout = new FileOutputStream(radio)
println(radio.toPath().getFileName)
} catch {
case e: FileNotFoundException => return AnyResponseHelper.internal_server_error("Cannot create radio map due to Server FileIO error!")
}
var floorFetched: Long = 0l
try {
floorFetched = ProxyDataSource.getIDatasource.dumpRssLogEntriesByBuildingFloor(fout, buid, floor_number)
try {
fout.close()
} catch {
case e: IOException => LPLogger.error("Error while closing the file output stream for the dumped rss logs")
}
} catch {
case e: DatasourceException => return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage + "]")
}
if (floorFetched != 0) {

try {
val folder = rmapDir.toString
val radiomap_filename = new File(folder + AnyplaceServerAPI.URL_SEPARATOR + "indoor-radiomap.txt")
.getAbsolutePath
var radiomap_mean_filename = radiomap_filename.replace(".txt", "-mean.txt")
var radiomap_rbf_weights_filename = radiomap_filename.replace(".txt", "-weights.txt")
var radiomap_parameters_filename = radiomap_filename.replace(".txt", "-parameters.txt")
val rm = new RadioMap(new File(folder), radiomap_filename, "", -110)
if (!rm.createRadioMap()) {
return AnyResponseHelper.internal_server_error("Error while creating Radio Map on-the-fly!")
}
val api = AnyplaceServerAPI.SERVER_API_ROOT
var pos = radiomap_mean_filename.indexOf("radiomaps_frozen")
radiomap_mean_filename = api + radiomap_mean_filename.substring(pos)
pos = radiomap_rbf_weights_filename.indexOf("radiomaps_frozen")
radiomap_rbf_weights_filename = api + radiomap_rbf_weights_filename.substring(pos)
pos = radiomap_parameters_filename.indexOf("radiomaps_frozen")
radiomap_parameters_filename = api + radiomap_parameters_filename.substring(pos)
} catch {
case e: Exception => return AnyResponseHelper.internal_server_error("Error while creating Radio Map on-the-fly! : " + e.getMessage)
}


val source = scala.io.Source.fromFile(rmapDir.getAbsolutePath + AnyplaceServerAPI.URL_SEPARATOR + "indoor-radiomap.txt")
val lines = try source.mkString finally source.close()
radiomap_mean_filename.add(floor_number)
rss_log_files.add(lines)
}
else {
radiomap_mean_filename.add("")
}
}
// everything is ok
val res = JsonObject.empty()
res.put("map_url_mean", radiomap_mean_filename)
res.put("rss_log_files", rss_log_files)
return AnyResponseHelper.ok(res, "Successfully served radio map.")
}

inner(request)
}

private def storeRadioMapToDB(infile: File): String = {
var line: String = null
var fr: FileReader = null
Expand All @@ -335,7 +460,7 @@ object AnyplacePosition extends play.api.mvc.Controller {
fr = new FileReader(infile)
bf = new BufferedReader(fr)
while ( {
line = bf.readLine;
line = bf.readLine
line != null
}) {
if (line.startsWith("# Timestamp")) //continue
Expand Down
53 changes: 53 additions & 0 deletions server/app/utils/AnyPlaceTilerHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,57 @@ object AnyPlaceTilerHelper {
}
true
}

def tileImageWithZoom(imageFile: File, lat: String, lng: String, zoom:String): Boolean = {
if (!imageFile.isFile || !imageFile.canRead()) {
return false
}
val imageDir = imageFile.getParentFile
if (!imageDir.isDirectory || !imageDir.canWrite() || !imageDir.canRead()) {
throw new AnyPlaceException("Server do not have the permissions to tile the passed argument[" +
imageFile.toString +
"]")
}
val pb = new ProcessBuilder(ANYPLACE_TILER_SCRIPT_START, imageFile.getAbsolutePath.toString, lat,
lng,"-DISLOG",zoom)
val log = new File(imageDir, "anyplace_tiler_" + imageFile.getName + ".log")
pb.redirectErrorStream(true)
pb.redirectOutput(ProcessBuilder.Redirect.appendTo(log))
try {
val p = pb.start()
val is = p.getInputStream
val br = new BufferedReader(new InputStreamReader(is))
var line = br.readLine()
while (line != null) {
println(">" + line)
line = br.readLine()
}
p.waitFor()
if (p.exitValue() != 0) {
val err = "Tiling for image[" + imageFile.toString + "] failed with exit code[" +
p.exitValue() +
"]!"
Logger.error(err)
throw new AnyPlaceException(err)
}
} catch {
case e: IOException => {
val err = "Tiling for image[" + imageFile.toString + "] failed with IOException[" +
e.getMessage +
"]!"
Logger.error(err)
throw new AnyPlaceException(err)
}
case e: InterruptedException => {
val err = "Tiling for image[" + imageFile.toString + "] failed with InterruptedException[" +
e.getMessage +
"]!"
Logger.error(err)
throw new AnyPlaceException(err)
}
}
true
}
}


2 changes: 1 addition & 1 deletion server/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ mappings in Universal ++= directory(baseDirectory.value / "floor_plans")

name := "anyplace_v3"

version := "3.0"
version := "4.0"

scalaVersion := "2.11.7"

Expand Down
Loading

0 comments on commit bbc5a7b

Please sign in to comment.