143 lines
3.4 KiB
PHP
143 lines
3.4 KiB
PHP
<?php
|
|
|
|
namespace germanairlinesva\file\recording;
|
|
|
|
class Recording
|
|
{
|
|
private const ident = "VGAR";
|
|
private const header_unpack = "a4ident/Cversion";
|
|
private const segment_unpack = "Vtime/Saltitude/Sgroundspeed/elatitude/elongitude";
|
|
|
|
private string $file_path = "";
|
|
|
|
private array $segments = [];
|
|
|
|
public function __construct(string $path)
|
|
{
|
|
$this->file_path = $path;
|
|
|
|
$this->read();
|
|
}
|
|
|
|
/**
|
|
* Generates a json representation
|
|
*
|
|
* @return array Json representation with path as geoJSON and profile as array
|
|
*/
|
|
public function to_json(): array
|
|
{
|
|
$path = [
|
|
"type" => "FeatureCollection",
|
|
"features" => [
|
|
0 => [
|
|
"type" => "Feature",
|
|
"properties" => [
|
|
"stroke" => "#ff0000",
|
|
"stroke-width" => 2,
|
|
"stroke-opacity" => 1
|
|
],
|
|
"geometry" => [
|
|
"type" => "LineString",
|
|
"coordinates" => []
|
|
]
|
|
]
|
|
]
|
|
];
|
|
$path["features"][0]["geometry"]["coordinates"] = array_map(function ($segment) {
|
|
return array($segment["longitude"], $segment["latitude"]);
|
|
}, $this->segments);
|
|
|
|
$profile = array_map(function ($segment) {
|
|
return array("altitude" => $segment["altitude"], "groundspeed" => $segment["groundspeed"]);
|
|
}, $this->segments);
|
|
|
|
return ["path" => $path, "profile" => $profile];
|
|
}
|
|
|
|
/**
|
|
* Generates a json string representation
|
|
*
|
|
* @return string Json string representation with path as geoJSON and profile as array
|
|
*/
|
|
public function to_json_string(): string
|
|
{
|
|
return json_encode($this->to_json());
|
|
}
|
|
|
|
/**
|
|
* Reads recording
|
|
*/
|
|
private function read()
|
|
{
|
|
if (!file_exists($this->file_path)) {
|
|
throw new \InvalidArgumentException("File not found");
|
|
}
|
|
|
|
$file = fopen($this->file_path, "rb");
|
|
if ($file) {
|
|
flock($file, LOCK_SH);
|
|
|
|
$version = $this->read_header($file);
|
|
|
|
if ($version == 1) {
|
|
while ($this->read_segment_1($file) != false);
|
|
}
|
|
|
|
flock($file, LOCK_UN);
|
|
fclose($file);
|
|
} else {
|
|
throw new \Exception("fopen Error");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reads one segment entry
|
|
*
|
|
* @param resource $file File handle
|
|
*
|
|
* @return true If not EOF
|
|
* @return false If EOF
|
|
*
|
|
* @throws InvalidArgumentException If file is not a resource
|
|
*/
|
|
private function read_segment_1($file): bool
|
|
{
|
|
if (false === is_resource($file)) {
|
|
throw new \InvalidArgumentException(sprintf('Argument must be a valid resource type. %s given.', gettype($file)));
|
|
}
|
|
$data = fread($file, 24);
|
|
if ($data) {
|
|
array_push($this->segments, unpack(Recording::segment_unpack, $data));
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Reads the file header
|
|
*
|
|
* @param resource $file File handle
|
|
*
|
|
* @return string File version
|
|
*
|
|
* @throws InvalidArgumentException If file is not a resource
|
|
* @throws UnexpectedValueException If ident mismatches
|
|
*/
|
|
private function read_header($file): string
|
|
{
|
|
if (false === is_resource($file)) {
|
|
throw new \InvalidArgumentException(sprintf('Argument must be a valid resource type. %s given.', gettype($file)));
|
|
}
|
|
|
|
$header = unpack(Recording::header_unpack, fread($file, 5));
|
|
|
|
if ($header["ident"] !== Recording::ident) {
|
|
throw
|
|
new \UnexpectedValueException(sprintf("Ident mismatch. Got %s, expected %s", $header["ident"], Recording::ident));
|
|
}
|
|
|
|
return $header["version"];
|
|
}
|
|
}
|