server.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. const express = require('express');
  2. const { Bundle, Client } = require('node-osc');
  3. const path = require('path');
  4. const bodyParser = require('body-parser');
  5. const app = express();
  6. const oscClient = new Client('127.0.0.1', 3333);
  7. let alive = [];
  8. let fseq;
  9. const objTriangle = [] ;
  10. function getHypotenuse(touch1, touch2) {
  11. const x = Math.abs(touch1.x - touch2.x);
  12. const y = Math.abs(touch1.y - touch2.y);
  13. return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  14. }
  15. function getTop(dotTrio) {
  16. const dist01 = getHypotenuse(dotTrio[0], dotTrio[1]);
  17. const dist02 = getHypotenuse(dotTrio[0], dotTrio[2]);
  18. const dist12 = getHypotenuse(dotTrio[1], dotTrio[2]);
  19. const diff01m02 = Math.abs(dist01 - dist02);
  20. const diff01m12 = Math.abs(dist01 - dist12);
  21. const diff02m12 = Math.abs(dist02 - dist12);
  22. if (diff01m02 < diff02m12 && diff01m02 < diff01m12) {return 0;}
  23. else if (diff01m12<diff01m02 && diff01m12<diff02m12) {return 1;}
  24. else if (diff02m12<diff01m02 && diff02m12<diff01m12) {return 2;}
  25. }
  26. function getAngleApex(dotTrio, topIndex) {
  27. let dotA;
  28. let dotB;
  29. let dotC;
  30. dotB = dotTrio[topIndex];
  31. if (topIndex == 0) {
  32. dotA = dotTrio[1];
  33. dotC = dotTrio[2];
  34. }
  35. else if (topIndex == 1) {
  36. dotA = dotTrio[0];
  37. dotC = dotTrio[2];
  38. }
  39. else if (topIndex == 2) {
  40. dotA = dotTrio[0];
  41. dotC = dotTrio[1];
  42. }
  43. const AB = [dotB.x - dotA.x, dotB.y - dotA.y] ;
  44. const CB = [dotB.x - dotC.x, dotB.y - dotC.y] ;
  45. const dotProd = (AB[0] * CB[0] + AB[1] * CB[1]);
  46. const crossProd = (AB[0]*CB[1] - AB[1] * CB[0]);
  47. const alpha = Math.atan2(crossProd, dotProd);
  48. //return alpha ;
  49. return Math.floor(alpha * 180. / Math.PI + 0.5) ;
  50. }
  51. function getOrientation(dotTrio, topIndex) {
  52. let dotA;
  53. let dotB;
  54. let dotC;
  55. dotB = dotTrio[topIndex];
  56. if (topIndex == 0) {
  57. dotA = dotTrio[1];
  58. dotC = dotTrio[2];
  59. }
  60. else if (topIndex == 1) {
  61. dotA = dotTrio[0];
  62. dotC = dotTrio[2];
  63. }
  64. else if (topIndex == 2) {
  65. dotA = dotTrio[0];
  66. dotC = dotTrio[1];
  67. }
  68. const middlePt = [(dotA.x+dotC.x)/2 ,(dotA.y+dotC.y)/2 ] ;
  69. let diff = [dotB.x - middlePt[0], dotB.y - middlePt[1]] ;
  70. const length = Math.sqrt(Math.pow(diff[0],2) + Math.pow(diff[1], 2) ) ;
  71. //normalize diff
  72. diff = [diff[0]/length, diff[1]/length];
  73. const rad = Math.atan2(diff[0], diff[1]) ;
  74. return Math.floor( -1 * rad * 180 / Math.PI) ;
  75. //return length ;
  76. }
  77. const server = require('http').Server(app);
  78. app.use(bodyParser.json());
  79. app.use(bodyParser.urlencoded({extended:true}));
  80. app.use(express.static('./frontend/assets'));
  81. app.get('/', function (req, res) {
  82. res.sendFile('./frontend/index.html', { root: path.resolve(__dirname + '/..') })
  83. });
  84. app.post('/json', function (req, res) {
  85. if (req.body.debug) {
  86. //console.log(req.body);
  87. }
  88. let oscBundle;
  89. if (req.body.event === 'touchend') {
  90. fseq = fseq ? fseq + 1 : 1;
  91. const aliveMessage = [ '/tuio/2Dcur', 'alive' ].concat(alive);
  92. oscBundle = new Bundle(
  93. [ '/tuio/2Dcur', 'source', `tangibles${req.body.section.toString()}@127.0.0.1` ],
  94. aliveMessage,
  95. [ '/tuio/2Dcur', 'fseq', fseq ],
  96. [
  97. '/tuio/2Dcur',
  98. 'del',
  99. req.body.changedTouches[0].identifier
  100. ]
  101. );
  102. oscClient.send(oscBundle, () => {
  103. const index = alive.indexOf(req.body.changedTouches[0].identifier);
  104. alive.splice(index, 1);
  105. if (alive.length === 0) {
  106. oscBundle = new Bundle(
  107. [ '/tuio/2Dcur', 'source', `tangibles${req.body.section.toString()}@127.0.0.1` ],
  108. [ '/tuio/2Dcur', 'alive' ],
  109. [ '/tuio/2Dcur', 'fseq', fseq ]
  110. );
  111. oscClient.send(oscBundle, () => {
  112. res.status(200).json(JSON.stringify(req.body));
  113. fseq = 0;
  114. });
  115. } else {
  116. res.status(200).send();
  117. }
  118. });
  119. } else {
  120. if (req.body.changedTouches && req.body.changedTouches.length && req.body.changedTouches.length > 0) {
  121. fseq = fseq ? fseq + 1 : 1;
  122. const touches = Object.keys(req.body.changedTouches);
  123. const aliveMessage = [ '/tuio/2Dcur', 'alive' ].concat(alive);
  124. touches.forEach(touch => {
  125. const id = req.body.changedTouches[touch].identifier;
  126. if (!alive.includes(id)) {
  127. alive.push(id);
  128. aliveMessage.push(id);
  129. }
  130. });
  131. /* Listage de tous les points */
  132. const dots = [];
  133. touches.forEach(function(touch) {
  134. dots.push({
  135. id: req.body.changedTouches[touch].identifier,
  136. x: req.body.changedTouches[touch].clientX,
  137. y: req.body.changedTouches[touch].clientY
  138. });
  139. });
  140. // console.log(dots, dots.length);
  141. /* Listage des segments */
  142. const segments = [];
  143. if (dots.length > 2) {
  144. for (var i = 0; i < dots.length; i++) {
  145. for (var j = 0; j < dots.length; j++) {
  146. if (j !== i) {
  147. /* on vérifie que le segment n'est pas déjà listé */
  148. const alreadyExists = segments.find(segment => {
  149. return segment.identifiers.includes(i) && segment.identifiers.includes(j);
  150. });
  151. /* on calcule la taille du segment (l'hypoténuse) */
  152. var hyp = getHypotenuse(dots[i], dots[j]);
  153. /* on garde uniquement les segments inférieurs à 550px
  154. * cette valeur devra être une variable de configuration */
  155. if (!alreadyExists && hyp <= 750) {
  156. segments.push({
  157. identifiers: [i, j],
  158. x1: dots[i].x,
  159. x2: dots[j].x,
  160. y1: dots[i].y,
  161. y2: dots[j].y,
  162. hyp
  163. });
  164. }
  165. }
  166. }
  167. }
  168. }
  169. // console.log(segments, segments.length);
  170. /* Listage des triangles */
  171. const triangles = [];
  172. /* on boucle sur les segments */
  173. segments.forEach((segment) => {
  174. const dot1 = segment.identifiers[0];
  175. const dot2 = segment.identifiers[1];
  176. /* on vérifie que le triangle n'est pas déjà listé */
  177. const alreadyExists = triangles.find(triangle => {
  178. return triangle.includes(dot1) && triangle.includes(dot2);
  179. });
  180. if (!alreadyExists) {
  181. /* on cherche les segments qui contiennent un des 2 points du segment actuel
  182. * ex: si le segment actuel est AB, on cherche un segment contenant A (pour AC) et un autre contenant B (pour BC) */
  183. const found1 = segments.findIndex(seg => {
  184. return (seg.identifiers.includes(dot1) && !seg.identifiers.includes(dot2));
  185. });
  186. const found2 = segments.findIndex(seg => {
  187. return (seg.identifiers.includes(dot2) && !seg.identifiers.includes(dot1));
  188. });
  189. /* si on trouve bien les 2 segments (AC et BC), on peut créer un triangle */
  190. if (found1 !== -1 && found2 !== -1) {
  191. /* on devine quel est le 3ème point du triangle par rapport au segment actuel (le point C par rapport au segment AB) */
  192. const dot3 = segments[found1].identifiers.find(identifier => {
  193. return identifier !== dot1 && identifier !== dot2;
  194. });
  195. triangles.push([dot1, dot2, dot3]);
  196. }
  197. }
  198. });
  199. console.log(triangles, triangles.length);
  200. //MOD TITI
  201. //objet pour stocker les informations des triangles identifiés (points, centre, apexAngle, orientation, indice apex, width, height)
  202. objTriangle = {} ;
  203. /* Définition de l'apex */
  204. triangles.forEach(triangle => {
  205. objTriangle.dots = [];
  206. objTriangle.dots[0] = dots[triangle[0]];
  207. objTriangle.dots[1] = dots[triangle[1]];
  208. objTriangle.dots[2] = dots[triangle[2]];
  209. objTriangle.apex = getTop(objTriangle.dots);
  210. objTriangle.center = [
  211. (objTriangle.dots[0].x+objTriangle.dots[1].x+objTriangle.dots[2].x)/3 ,
  212. (objTriangle.dots[0].y+objTriangle.dots[1].y+objTriangle.dots[2].y)/3
  213. ];
  214. objTriangle.angleApex = getAngleApex(objTriangle.dots, objTriangle.apex) ;
  215. objTriangle.orientation = getOrientation(objTriangle.dots, objTriangle.apex) ;
  216. // /* on récupère les 3 côtés (segments) du triangle */
  217. // const segment1 = segments.find(segment => {
  218. // return segment.identifiers.includes(triangle[0]) && segment.identifiers.includes(triangle[1]);
  219. // });
  220. // const segment2 = segments.find(segment => {
  221. // return segment.identifiers.includes(triangle[1]) && segment.identifiers.includes(triangle[2]);
  222. // });
  223. // const segment3 = segments.find(segment => {
  224. // return segment.identifiers.includes(triangle[0]) && segment.identifiers.includes(triangle[2]);
  225. // });
  226. // /* on trouve quel côté est le plus court
  227. // * NOTE: dans notre cas, l'apex sera toujours le point opposé au plus petit côté
  228. // * cette méthode n'est pas généralisable à d'autres projets */
  229. // const smallestSegment = [segment1, segment2, segment3].reduce(function(prev, current) {
  230. // return (prev.hyp < current.hyp) ? prev : current
  231. // });
  232. // /* on déduit quel point du triangle est l'apex */
  233. // const apexDot = triangle.find(dot => {
  234. // return dot !== smallestSegment.identifiers[0] && dot !== smallestSegment.identifiers[1];
  235. // });
  236. console.log(objTriangle.apex);
  237. console.log("centerPos : " + objTriangle.center + " orientation : " + objTriangle.orientation);
  238. /* Reste à faire:
  239. * trouver la valeur de l'angle de l'apex (théorème des cosinus)
  240. * trouver le "centre" du triangle (via les orthocentres ou médianes??)
  241. * déduire l'orientation du triangle
  242. */
  243. });
  244. //plante vite
  245. // if (objTriangle.dots != undefined){
  246. // let oscBundleObj ;
  247. // oscBundleObj = new Bundle(
  248. // [ '/tuio/2Dobj', 'source', `tangibles${req.body.section.toString()}@127.0.0.1` ],
  249. // [ '/tuio/2Dobj', 'alive', 1 ],
  250. // [
  251. // '/tuio/2Dobj',
  252. // 'set',
  253. // 1,
  254. // 1,
  255. // objTriangle.center[0],
  256. // objTriangle.center[1],
  257. // objTriangle.orientation,
  258. // 0.0,
  259. // 0.0,
  260. // 0.0,
  261. // 0.0,
  262. // 0.0
  263. // ],
  264. // [ '/tuio/2Dobj', 'fseq', fseq ]
  265. // );
  266. // // // objTriangle.forEach(triangleIndex => {
  267. // // // oscBundle.append(
  268. // // // [
  269. // // // '/tuio/2Dobj',
  270. // // // 'set',
  271. // // // triangleIndex,
  272. // // // triangleIndex,
  273. // // // objTriangle[triangleIndex].center[0],
  274. // // // objTriangle[triangleIndex].center[1],
  275. // // // objTriangle[triangleIndex].orientation,
  276. // // // 0.0,
  277. // // // 0.0,
  278. // // // 0.0,
  279. // // // 0.0,
  280. // // // 0.0
  281. // // // ]
  282. // // // );
  283. // // // });
  284. // console.log(oscBundleObj);
  285. // oscClient.send(oscBundleObj, () => {
  286. // res.status(200).json(JSON.stringify(req.body));
  287. // });
  288. // }
  289. // oscBundle = new Bundle(
  290. // [ '/tuio/2Dcur', 'source', `tangibles${req.body.section.toString()}@127.0.0.1` ],
  291. // aliveMessage,
  292. // [ '/tuio/2Dcur', 'fseq', fseq ]
  293. // );
  294. // touches.forEach(touch => {
  295. // oscBundle.append(
  296. // [
  297. // '/tuio/2Dcur',
  298. // 'set',
  299. // req.body.changedTouches[touch].identifier,
  300. // req.body.changedTouches[touch].clientX / req.body.screenW,
  301. // req.body.changedTouches[touch].clientY / req.body.screenH,
  302. // 0.0,
  303. // 0.0
  304. // ]
  305. // );
  306. // });
  307. oscBundle = new Bundle ;
  308. oscBundle.append([ '/tuio/2Dobj', 'alive', 1 ]);
  309. if (objTriangle.dots != undefined){
  310. oscBundle.append([
  311. '/tuio/2Dobj',
  312. 'set',
  313. 1,
  314. 1,
  315. objTriangle.center[0],
  316. objTriangle.center[1],
  317. objTriangle.orientation,
  318. 0.0,
  319. 0.0,
  320. 0.0,
  321. 0.0,
  322. 0.0
  323. ]);
  324. }
  325. oscBundle.append([ '/tuio/2Dobj', 'fseq', fseq ]);
  326. oscClient.send(oscBundle, () => {
  327. res.status(200).json(JSON.stringify(req.body));
  328. });
  329. } else {
  330. res.status(400).send();
  331. }
  332. }
  333. });
  334. server.listen(5001, function () {
  335. console.log('Votre app est disponible sur localhost:5001 !')
  336. });