MeasureInterface.class.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. <?php
  2. namespace Models {
  3. require_once 'Models/User.class.php';
  4. require_once 'Tools/Random.class.php';
  5. require_once 'Tools/FS.class.php';
  6. require_once 'Tools/UUID.class.php';
  7. class MeasureInterface {
  8. //
  9. protected $DataInterface;
  10. /**
  11. *
  12. */
  13. public function __construct($DataInterface) {
  14. $this->DataInterface = $DataInterface;
  15. }
  16. /**
  17. * Get media
  18. */
  19. public function measureGet($User, $patientID, $visitID) {
  20. // patient
  21. $statement = $this->DataInterface->DatabaseConnection->prepare(
  22. "SELECT patient.* FROM patient WHERE ID = :fk_patient"
  23. );
  24. $statement->bindParam(':fk_patient', $patientID);
  25. // Error check
  26. if(!$statement->execute()) {
  27. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  28. }
  29. $patient = $statement->fetchAll(\PDO::FETCH_ASSOC)[0];
  30. // visit
  31. $statement = $this->DataInterface->DatabaseConnection->prepare(
  32. "SELECT area, markers FROM visit WHERE ID = :fk_visit"
  33. );
  34. $statement->bindParam(':fk_visit', $visitID);
  35. // Error check
  36. if(!$statement->execute()) {
  37. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  38. }
  39. $data = $statement->fetchAll(\PDO::FETCH_ASSOC)[0];
  40. // media
  41. $statement = $this->DataInterface->DatabaseConnection->prepare(
  42. "SELECT ID, side, location, filename, metrics FROM media WHERE fk_visit = :fk_visit"
  43. );
  44. $statement->bindParam(':fk_visit', $visitID);
  45. // Error check
  46. if(!$statement->execute()) {
  47. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  48. }
  49. $media = $statement->fetchAll(\PDO::FETCH_ASSOC);
  50. foreach($media as &$m) {
  51. $m['metrics'] = json_decode($m['metrics']);
  52. // measures
  53. $m['measure'] = $this->getMeasures($m['ID']);
  54. }
  55. // settings
  56. $statement = $this->DataInterface->DatabaseConnection->prepare(
  57. "SELECT anon_percent FROM clinical_trial"
  58. );
  59. // Error check
  60. if(!$statement->execute()) {
  61. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  62. }
  63. $anon_percent = intval($statement->fetchAll(\PDO::FETCH_ASSOC)[0]['anon_percent']);
  64. return [
  65. 'result' => 'OK',
  66. 'patient' => $patient,
  67. 'area' => $data['area'],
  68. 'markers' => json_decode($data['markers']),
  69. 'media' => $media,
  70. 'anon_percent' => $anon_percent
  71. ];
  72. }
  73. /**
  74. * Complete
  75. */
  76. public function measureCompletePost($User, $data) {
  77. $userID = $User->ID;
  78. $statement = $this->DataInterface->DatabaseConnection->prepare(
  79. "SELECT password FROM user WHERE ID = $userID"
  80. );
  81. if(!$statement->execute()) {
  82. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  83. }
  84. $securedPassword = $statement->fetchAll(\PDO::FETCH_ASSOC)[0]['password'];
  85. if(\Tools\Crypto::verify($data['password'], $securedPassword)) {
  86. // update
  87. $statement = $this->DataInterface->DatabaseConnection->prepare(
  88. "UPDATE visit SET completed = NOW() WHERE ID = :visitID"
  89. );
  90. $statement->bindParam(':visitID', $data['visitID']);
  91. if(!$statement->execute()) {
  92. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  93. }
  94. }
  95. else {
  96. return ['result' => 'ERROR', 'reason' => 'bad_password', 'message' => 'Invalid password'];
  97. }
  98. return [
  99. 'result' => 'OK',
  100. ];
  101. }
  102. /**
  103. *
  104. */
  105. protected function getMeasures($fk_media) {
  106. // measures
  107. $statement = $this->DataInterface->DatabaseConnection->prepare(
  108. "SELECT * FROM measure WHERE fk_media = :fk_media ORDER BY ID DESC"
  109. );
  110. $statement->bindParam(':fk_media', $fk_media);
  111. // Error check
  112. if(!$statement->execute()) {
  113. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  114. }
  115. $measures = $statement->fetchAll(\PDO::FETCH_ASSOC);
  116. foreach($measures as &$measure) {
  117. $measure['points'] = json_decode($measure['points']);
  118. $measure['computation'] = json_decode($measure['computation']);
  119. }
  120. return $measures;
  121. }
  122. /**
  123. *
  124. */
  125. protected function useCredit($fk_user, $fk_media) {
  126. // user type
  127. $statement = $this->DataInterface->DatabaseConnection->prepare(
  128. "SELECT type FROM user WHERE ID = :fk_user"
  129. );
  130. $statement->bindParam(':fk_user', $fk_user);
  131. // Error check
  132. if(!$statement->execute()) {
  133. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  134. }
  135. $userType = $statement->fetchAll(\PDO::FETCH_ASSOC)[0]['type'];
  136. $targetID = $fk_user;
  137. if($userType=='reader') {
  138. // customer CRO
  139. $statement = $this->DataInterface->DatabaseConnection->prepare(
  140. "SELECT * FROM user WHERE type = 'cro' ORDER BY ID LIMIT 0,1"
  141. );
  142. // Error check
  143. if(!$statement->execute()) {
  144. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  145. }
  146. $customer = $statement->fetchAll(\PDO::FETCH_ASSOC);
  147. $targetID = $customer[0]['ID'];
  148. }
  149. // total purchased credits
  150. $statement = $this->DataInterface->DatabaseConnection->prepare(
  151. "SELECT SUM(count) AS purchased FROM credit WHERE ID_user = :fk_user"
  152. );
  153. $statement->bindParam(':fk_user', $targetID);
  154. // Error check
  155. if(!$statement->execute()) {
  156. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  157. }
  158. $purchased = intval($statement->fetchAll(\PDO::FETCH_ASSOC)[0]['purchased']);
  159. // total used credits
  160. $statement = $this->DataInterface->DatabaseConnection->prepare(
  161. "SELECT COUNT(ID) AS used FROM credit_usage WHERE fk_user = :fk_user"
  162. );
  163. $statement->bindParam(':fk_user', $targetID);
  164. // Error check
  165. if(!$statement->execute()) {
  166. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  167. }
  168. $used = intval($statement->fetchAll(\PDO::FETCH_ASSOC)[0]['used']);
  169. if($purchased-$used>0) {
  170. // usage on this media
  171. $statement = $this->DataInterface->DatabaseConnection->prepare(
  172. "SELECT ID FROM credit_usage WHERE fk_media = :fk_media AND fk_user = :fk_user"
  173. );
  174. $statement->bindParam(':fk_media', $fk_media);
  175. $statement->bindParam(':fk_user', $targetID);
  176. // Error check
  177. if(!$statement->execute()) {
  178. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  179. }
  180. // not used yet
  181. $media_credit = $statement->fetchAll(\PDO::FETCH_ASSOC);
  182. if(count($media_credit)==0) {
  183. $statement = $this->DataInterface->DatabaseConnection->prepare(
  184. "INSERT INTO credit_usage(fk_user, fk_media) VALUES(:fk_user, :fk_media)"
  185. );
  186. $statement->bindParam(':fk_user', $targetID);
  187. $statement->bindParam(':fk_media', $fk_media);
  188. // Error check
  189. if(!$statement->execute()) {
  190. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  191. }
  192. return $purchased-$used-1;
  193. }
  194. return $purchased-$used;
  195. }
  196. return false;
  197. }
  198. /**
  199. *
  200. */
  201. protected function cleanMeasures($fk_media, $keepPlaques, $imtType) {
  202. if($keepPlaques) {
  203. $keepPlaques = "AND type != 'plaque'";
  204. }
  205. else {
  206. $keepPlaques = '';
  207. }
  208. if($imtType===false) {
  209. // clean measures
  210. $statement = $this->DataInterface->DatabaseConnection->prepare(
  211. "DELETE FROM measure WHERE fk_media = :fk_media AND type != 'calibration' $keepPlaques"
  212. );
  213. $statement->bindParam(':fk_media', $fk_media);
  214. }
  215. else {
  216. // clean 'imt' of same type
  217. $typeNearWall = ($imtType=='near'?'true':'false');
  218. $statement = $this->DataInterface->DatabaseConnection->prepare(
  219. "DELETE FROM measure WHERE fk_media = :fk_media AND type = 'imt' AND JSON_EXTRACT(computation, \"$.nearWall\") = $typeNearWall"
  220. );
  221. $statement->bindParam(':fk_media', $fk_media);
  222. // Error check
  223. if(!$statement->execute()) {
  224. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  225. }
  226. // clean measures but 'imt'
  227. $statement = $this->DataInterface->DatabaseConnection->prepare(
  228. "DELETE FROM measure WHERE fk_media = :fk_media AND type != 'calibration' $keepPlaques AND type != 'imt'"
  229. );
  230. $statement->bindParam(':fk_media', $fk_media);
  231. }
  232. // Error check
  233. if(!$statement->execute()) {
  234. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  235. }
  236. return true;
  237. }
  238. /**
  239. *
  240. */
  241. public function generateFrame($data, $fps, $frame, &$filename) {
  242. $filename = $data['filename'];
  243. // video
  244. if($fps) {
  245. if(strpos($filename, '.dicom')!==false) {
  246. $filename = str_replace('.dicom','-'.$frame.'.jpeg', $filename);
  247. $dst = '../../storage/media/'.$data['visitID'].'/'.$filename;
  248. if(!file_exists($dst)) {
  249. $src = '../../storage/media/'.$data['visitID'].'/'.$data['filename'];
  250. $cmdLine = 'dcmj2pnm "'.$src.'" "'.$dst.'" +oj +Jq 100 +F '.($frame+1).' -v 2>&1';
  251. $output=null;
  252. $retval=null;
  253. exec($cmdLine, $output, $retval);
  254. // error
  255. if($retval !== 0 || count($output)<1) {
  256. return [
  257. 'result' => 'ERROR',
  258. 'cmdLine' => $cmdLine,
  259. 'output' => $output,
  260. 'retval' => $retval
  261. ];
  262. }
  263. }
  264. }
  265. else {
  266. $filename = str_replace('.mp4','-'.$frame.'.jpeg', $filename);
  267. $dst = '../../storage/media/'.$data['visitID'].'/'.$filename;
  268. if(!file_exists($dst)) {
  269. $ss = $frame;
  270. $fps = intval($fps);
  271. if($frame != 0) {
  272. $t = floor($frame / $fps);
  273. $r = $frame - ($t * $fps);
  274. $ss = $t + ($r * 1.0 / $fps);
  275. }
  276. $src = '../../storage/media/'.$data['visitID'].'/'.$data['filename'];
  277. $cmdLine = 'ffmpeg -ss '.$ss.' -i '.$src.' -q:v 1 -frames:v 1 '.$dst;
  278. $output=null;
  279. $retval=null;
  280. exec($cmdLine, $output, $retval);
  281. // error
  282. if($retval !== 0 || count($output)!==0) {
  283. return [
  284. 'result' => 'ERROR',
  285. 'cmdLine' => $cmdLine,
  286. 'output' => $output,
  287. 'retval' => $retval
  288. ];
  289. }
  290. }
  291. }
  292. }
  293. // image
  294. else {
  295. // dicom
  296. if(strpos($filename, '.dicom')!==false) {
  297. $filename = str_replace('.dicom','.jpeg', $filename);
  298. }
  299. }
  300. return true;
  301. }
  302. /**
  303. *
  304. */
  305. public function measureCalibrationPost($User, $data) {
  306. $userID = $User->ID;
  307. // calibration
  308. $statement = $this->DataInterface->DatabaseConnection->prepare(
  309. "UPDATE media SET metrics = JSON_SET(metrics, \"$.pxwidth\", :scale1+0, \"$.pxheight\", :scale2+0) WHERE filename = :filename AND fk_visit = :fk_visit"
  310. );
  311. $statement->bindParam(':filename', $data['filename']);
  312. $statement->bindParam(':fk_visit', $data['visitID']);
  313. $statement->bindParam(':scale1', $data['scale']);
  314. $statement->bindParam(':scale2', $data['scale']);
  315. // Error check
  316. if(!$statement->execute()) {
  317. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  318. }
  319. // media
  320. $statement = $this->DataInterface->DatabaseConnection->prepare(
  321. "SELECT ID, JSON_EXTRACT(metrics, \"$.fps\") AS fps FROM media WHERE filename = :filename AND fk_visit = :fk_visit"
  322. );
  323. $statement->bindParam(':filename', $data['filename']);
  324. $statement->bindParam(':fk_visit', $data['visitID']);
  325. // Error check
  326. if(!$statement->execute()) {
  327. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  328. }
  329. $fk_media = $statement->fetchAll(\PDO::FETCH_ASSOC)[0]['ID'];
  330. // Gen frame?
  331. $fps = $results[0]['fps'];
  332. $frame = intval($data['frame']);
  333. $filename = $data['filename'];
  334. $r = $this->generateFrame($data, $fps, $frame, $filename);
  335. if($r !== true) {
  336. return $r;
  337. }
  338. // clean measure
  339. $statement = $this->DataInterface->DatabaseConnection->prepare(
  340. "DELETE FROM measure WHERE fk_media = :fk_media"
  341. );
  342. $statement->bindParam(':fk_media', $fk_media);
  343. // Error check
  344. if(!$statement->execute()) {
  345. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  346. }
  347. // insert measure
  348. $statement = $this->DataInterface->DatabaseConnection->prepare(
  349. "INSERT INTO measure VALUES(0, 'calibration', :points, :computation, :fk_media, :frame, :fk_user, NOW())"
  350. );
  351. $points = json_encode($data['points'], JSON_NUMERIC_CHECK);
  352. $statement->bindParam(':points', $points);
  353. $computation = json_encode($data['computation'], JSON_NUMERIC_CHECK);
  354. $statement->bindParam(':computation', $computation);
  355. $statement->bindParam(':fk_media', $fk_media);
  356. $statement->bindParam(':frame', $data['frame']);
  357. $statement->bindParam(':fk_user', $userID);
  358. // Error check
  359. if(!$statement->execute()) {
  360. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  361. }
  362. $measureID = $this->DataInterface->DatabaseConnection->lastInsertId();
  363. return [
  364. 'result' => 'OK',
  365. 'scale' => floatval($data['scale']),
  366. 'measure' => array(
  367. 'ID' => $measureID,
  368. 'fk_media' => $fk_media,
  369. 'type' => 'calibration',
  370. 'points' => json_decode($points),
  371. 'frame' => intval($data['frame']),
  372. 'computation' => json_decode($computation)
  373. )
  374. ];
  375. }
  376. /**
  377. *
  378. */
  379. public function measureDistancePost($User, $data) {
  380. $userID = $User->ID;
  381. // media
  382. $statement = $this->DataInterface->DatabaseConnection->prepare(
  383. "SELECT ID, JSON_EXTRACT(metrics, \"$.fps\") AS fps FROM media WHERE filename = :filename AND fk_visit = :fk_visit"
  384. );
  385. $statement->bindParam(':filename', $data['filename']);
  386. $statement->bindParam(':fk_visit', $data['visitID']);
  387. // Error check
  388. if(!$statement->execute()) {
  389. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  390. }
  391. $results = $statement->fetchAll(\PDO::FETCH_ASSOC);
  392. if(count($results)==0) {
  393. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => $data['filename'], 'data' => $statement->errorInfo()];
  394. }
  395. $fk_media = $results[0]['ID'];
  396. // Gen frame?
  397. $fps = $results[0]['fps'];
  398. $frame = intval($data['frame']);
  399. $filename = $data['filename'];
  400. $r = $this->generateFrame($data, $fps, $frame, $filename);
  401. if($r !== true) {
  402. return $r;
  403. }
  404. // clean measure
  405. $this->cleanMeasures($fk_media, false, false);
  406. // insert measure
  407. $statement = $this->DataInterface->DatabaseConnection->prepare(
  408. "INSERT INTO measure VALUES(0, :type, :points, :computation, :fk_media, :frame, :fk_user, NOW())"
  409. );
  410. $statement->bindParam(':type', $data['type']);
  411. $points = json_encode($data['points'], JSON_NUMERIC_CHECK);
  412. $statement->bindParam(':points', $points);
  413. $computation = json_encode($data['computation'], JSON_NUMERIC_CHECK);
  414. $statement->bindParam(':computation', $computation);
  415. $statement->bindParam(':fk_media', $fk_media);
  416. $statement->bindParam(':frame', $data['frame']);
  417. $statement->bindParam(':fk_user', $userID);
  418. // Error check
  419. if(!$statement->execute()) {
  420. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  421. }
  422. $measureID = $this->DataInterface->DatabaseConnection->lastInsertId();
  423. return [
  424. 'result' => 'OK',
  425. 'measure' => array(
  426. 'ID' => $measureID,
  427. 'fk_media' => $fk_media,
  428. 'type' => $data['type'],
  429. 'points' => json_decode($points),
  430. 'frame' => intval($data['frame']),
  431. 'computation' => json_decode($computation)
  432. ),
  433. 'measures' => $this->getMeasures($fk_media)
  434. ];
  435. }
  436. /**
  437. *
  438. */
  439. public function measureAreaPost($User, $data) {
  440. $userID = $User->ID;
  441. // media
  442. $statement = $this->DataInterface->DatabaseConnection->prepare(
  443. "SELECT ID, JSON_EXTRACT(metrics, \"$.fps\") AS fps FROM media WHERE filename = :filename AND fk_visit = :fk_visit"
  444. );
  445. $statement->bindParam(':filename', $data['filename']);
  446. $statement->bindParam(':fk_visit', $data['visitID']);
  447. // Error check
  448. if(!$statement->execute()) {
  449. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  450. }
  451. $results = $statement->fetchAll(\PDO::FETCH_ASSOC);
  452. if(count($results)==0) {
  453. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => $data['filename'], 'data' => $statement->errorInfo()];
  454. }
  455. $fk_media = $results[0]['ID'];
  456. // Gen frame?
  457. $fps = $results[0]['fps'];
  458. $frame = intval($data['frame']);
  459. $filename = $data['filename'];
  460. $r = $this->generateFrame($data, $fps, $frame, $filename);
  461. if($r !== true) {
  462. return $r;
  463. }
  464. // clean measure
  465. $this->cleanMeasures($fk_media, false, false);
  466. // insert measure
  467. $statement = $this->DataInterface->DatabaseConnection->prepare(
  468. "INSERT INTO measure VALUES(0, 'area', :points, :computation, :fk_media, :frame, :fk_user, NOW())"
  469. );
  470. $points = json_encode($data['points'], JSON_NUMERIC_CHECK);
  471. $statement->bindParam(':points', $points);
  472. $computation = json_encode($data['computation'], JSON_NUMERIC_CHECK);
  473. $statement->bindParam(':computation', $computation);
  474. $statement->bindParam(':fk_media', $fk_media);
  475. $statement->bindParam(':frame', $data['frame']);
  476. $statement->bindParam(':fk_user', $userID);
  477. // Error check
  478. if(!$statement->execute()) {
  479. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  480. }
  481. $measureID = $this->DataInterface->DatabaseConnection->lastInsertId();
  482. return [
  483. 'result' => 'OK',
  484. 'measure' => array(
  485. 'ID' => $measureID,
  486. 'fk_media' => $fk_media,
  487. 'type' => 'area',
  488. 'points' => json_decode($points),
  489. 'frame' => intval($data['frame']),
  490. 'computation' => json_decode($computation)
  491. ),
  492. 'measures' => $this->getMeasures($fk_media)
  493. ];
  494. }
  495. /**
  496. *
  497. */
  498. public function measureImtPost($User, $data) {
  499. $userID = $User->ID;
  500. // media
  501. $statement = $this->DataInterface->DatabaseConnection->prepare(
  502. "SELECT ID, JSON_EXTRACT(metrics, \"$.fps\") AS fps FROM media WHERE filename = :filename AND fk_visit = :fk_visit"
  503. );
  504. $statement->bindParam(':filename', $data['filename']);
  505. $statement->bindParam(':fk_visit', $data['visitID']);
  506. // Error check
  507. if(!$statement->execute()) {
  508. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  509. }
  510. $results = $statement->fetchAll(\PDO::FETCH_ASSOC);
  511. if(count($results)==0) {
  512. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => $data['filename'], 'data' => $statement->errorInfo()];
  513. }
  514. $fk_media = $results[0]['ID'];
  515. // use credit
  516. $credit_left = $this->useCredit($userID, $fk_media);
  517. if($credit_left === false) {
  518. return ['result' => 'ERROR', 'reason' => 'no_credit'];
  519. }
  520. // Gen frame?
  521. $fps = $results[0]['fps'];
  522. $frame = intval($data['frame']);
  523. $filename = $data['filename'];
  524. $r = $this->generateFrame($data, $fps, $frame, $filename);
  525. if($r !== true) {
  526. return $r;
  527. }
  528. $pt0x = $data['points'][0]['x'];
  529. $pt0y = $data['points'][0]['y'];
  530. $pt1x = $data['points'][1]['x'];
  531. $pt1y = $data['points'][1]['y'];
  532. $pxwidth = $data['pxwidth'];
  533. $pxheight = $data['pxheight'];
  534. $relativePath = '../../storage/media/'.$data['visitID'].'/'.$filename;
  535. $cmdLine = '../../bin/math-imt -platform offscreen -image='.$relativePath.' -metric='.$pxwidth.'x'.$pxheight.' -point1='.$pt0x.'x'.$pt0y.' -point2='.$pt1x.'x'.$pt1y;
  536. $output=null;
  537. $retval=null;
  538. exec($cmdLine, $output, $retval);
  539. if($retval !== 0 || count($output)<1) {
  540. return [
  541. 'result' => 'ERROR',
  542. 'cmdLine' => $cmdLine,
  543. 'output' => $output,
  544. 'retval' => $retval
  545. ];
  546. }
  547. $resComputation = json_decode($output[0]);
  548. // clean measure
  549. $cln = $this->cleanMeasures($fk_media, false, $resComputation->nearWall?'near':'far');
  550. if($cln !== true) {
  551. return $cln;
  552. }
  553. // insert measure
  554. $statement = $this->DataInterface->DatabaseConnection->prepare(
  555. "INSERT INTO measure VALUES(0, :type, :points, :computation, :fk_media, :frame, :fk_user, NOW())"
  556. );
  557. $type = 'imt';
  558. $statement->bindParam(':type', $type);
  559. $points = json_encode($data['points'], JSON_NUMERIC_CHECK);
  560. $statement->bindParam(':points', $points);
  561. $computation = json_encode($resComputation, JSON_NUMERIC_CHECK);
  562. $statement->bindParam(':computation', $computation);
  563. $statement->bindParam(':fk_media', $fk_media);
  564. $statement->bindParam(':frame', $data['frame']);
  565. $statement->bindParam(':fk_user', $userID);
  566. // Error check
  567. if(!$statement->execute()) {
  568. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  569. }
  570. $measureID = $this->DataInterface->DatabaseConnection->lastInsertId();
  571. return [
  572. 'result' => 'OK',
  573. 'cmdLine' => $cmdLine,
  574. 'measure' => array(
  575. 'ID' => $measureID,
  576. 'fk_media' => $fk_media,
  577. 'type' => $type,
  578. 'points' => json_decode($points),
  579. 'frame' => intval($data['frame']),
  580. 'computation' => json_decode($output[0])
  581. ),
  582. 'measures' => $this->getMeasures($fk_media),
  583. 'credit_left' => $credit_left
  584. ];
  585. }
  586. /**
  587. *
  588. */
  589. public function measurePlaquePost($User, $data) {
  590. $userID = $User->ID;
  591. // media
  592. $statement = $this->DataInterface->DatabaseConnection->prepare(
  593. "SELECT ID, JSON_EXTRACT(metrics, \"$.fps\") AS fps FROM media WHERE filename = :filename AND fk_visit = :fk_visit"
  594. );
  595. $statement->bindParam(':filename', $data['filename']);
  596. $statement->bindParam(':fk_visit', $data['visitID']);
  597. // Error check
  598. if(!$statement->execute()) {
  599. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  600. }
  601. $results = $statement->fetchAll(\PDO::FETCH_ASSOC);
  602. if(count($results)==0) {
  603. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => $data['filename'], 'data' => $statement->errorInfo()];
  604. }
  605. $fk_media = $results[0]['ID'];
  606. // use credit
  607. $credit_left = $this->useCredit($userID, $fk_media);
  608. if($credit_left === false) {
  609. return ['result' => 'ERROR', 'reason' => 'no_credit'];
  610. }
  611. // Gen frame?
  612. $fps = $results[0]['fps'];
  613. $frame = intval($data['frame']);
  614. $filename = $data['filename'];
  615. $r = $this->generateFrame($data, $fps, $frame, $filename);
  616. if($r !== true) {
  617. return $r;
  618. }
  619. // clean measure
  620. $cln = $this->cleanMeasures($fk_media, $data['keepPlaques']!='false', false);
  621. if($cln !== true) {
  622. return $cln;
  623. }
  624. $points = [];
  625. for($i=0; $i<count($data['points']); $i++) {
  626. $points[] = implode(",", $data['points'][$i]);
  627. }
  628. $pxwidth = $data['pxwidth'];
  629. $pxheight = $data['pxheight'];
  630. $relativePath = '../../storage/media/'.$data['visitID'].'/'.$filename;
  631. $pts = implode(";", $points);
  632. $cmdLine = "../../bin/math-plaque -platform offscreen -image=$relativePath -metric=$pxwidth"."x"."$pxheight -points=\"".$pts."\"";
  633. $output=null;
  634. $retval=null;
  635. exec($cmdLine, $output, $retval);
  636. if($retval !== 0 || count($output)<1) {
  637. return [
  638. 'result' => 'ERROR',
  639. 'cmdLine' => $cmdLine,
  640. 'output' => $output,
  641. 'retval' => $retval
  642. ];
  643. }
  644. $output = json_decode($output[0]);
  645. if(count($output->ptsTrouvesFin)==0) {
  646. return [
  647. 'result' => 'ERROR',
  648. 'reason' => 'algo_failed'
  649. ];
  650. }
  651. // insert measure
  652. $statement = $this->DataInterface->DatabaseConnection->prepare(
  653. "INSERT INTO measure VALUES(0, :type, :points, :computation, :fk_media, :frame, :fk_user, NOW())"
  654. );
  655. $type = 'plaque';
  656. $statement->bindParam(':type', $type);
  657. $points = json_encode($data['points'], JSON_NUMERIC_CHECK);
  658. $statement->bindParam(':points', $points);
  659. $computation = json_encode($output, JSON_NUMERIC_CHECK);
  660. $statement->bindParam(':computation', $computation);
  661. $statement->bindParam(':fk_media', $fk_media);
  662. $statement->bindParam(':frame', $data['frame']);
  663. $statement->bindParam(':fk_user', $userID);
  664. // Error check
  665. if(!$statement->execute()) {
  666. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  667. }
  668. $measureID = $this->DataInterface->DatabaseConnection->lastInsertId();
  669. return [
  670. 'result' => 'OK',
  671. 'cmdLine' => $cmdLine,
  672. 'measure' => array(
  673. 'ID' => $measureID,
  674. 'fk_media' => $fk_media,
  675. 'type' => $type,
  676. 'points' => json_decode($points),
  677. 'frame' => intval($data['frame']),
  678. 'computation' => $output
  679. ),
  680. 'measures' => $this->getMeasures($fk_media),
  681. 'credit_left' => $credit_left
  682. ];
  683. }
  684. }
  685. }