vid.dart 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. import 'dart:math';
  2. import 'dart:math' as math;
  3. import 'dart:typed_data';
  4. import 'dart:ui' as ui;
  5. import 'package:fis_vid/processors/processor.dart';
  6. import 'package:flutter/material.dart';
  7. import 'package:flutter/services.dart';
  8. import 'package:get/get.dart';
  9. import 'package:quiver/core.dart';
  10. import 'package:vid/us/vid_us_2d_visual.dart';
  11. import 'package:vid/us/vid_us_image.dart';
  12. import 'package:vid/us/vid_us_image_data.dart';
  13. import 'package:vid/us/vid_us_physical_coordinate.dart';
  14. import 'package:vid/us/vid_us_visual_area_type.dart';
  15. import 'package:vid/us/vid_us_visual_type.dart';
  16. import 'draw.dart';
  17. class Tuple<T1, T2> {
  18. final T1 item1;
  19. final T2 item2;
  20. const Tuple(this.item1, this.item2);
  21. factory Tuple.fromList(List items) {
  22. if (items.length != 2) {
  23. throw ArgumentError(
  24. "Tuple.fromList: argument `items` must have length 2.");
  25. }
  26. return Tuple(items[0] as T1, items[1] as T2);
  27. }
  28. List toList() => [item1, item2];
  29. @override
  30. String toString() => '[$item1, $item2]';
  31. @override
  32. bool operator ==(Object other) =>
  33. other is Tuple && other.item1 == item1 && other.item2 == item2;
  34. @override
  35. int get hashCode => hash2(item1, item2);
  36. }
  37. class MatrixUtil {
  38. static List<DMatrix> multiplyMatrix(DMatrix matrix1, DMatrix matrix2) {
  39. // ignore: prefer_function_declarations_over_variables
  40. final reutrnFn = () => [matrix1, matrix2];
  41. MatrixTypes types = matrix1._type;
  42. MatrixTypes types2 = matrix2._type;
  43. if (types2 != MatrixTypes.identify) {
  44. if (types == MatrixTypes.identify) {
  45. matrix1 = matrix2;
  46. } else if (types2 == MatrixTypes.translation) {
  47. matrix1._offsetX += matrix2._offsetX;
  48. matrix1._offsetY += matrix2._offsetY;
  49. if (types != MatrixTypes.unknown) {
  50. var typeIdx = matrix1._type.index;
  51. typeIdx |= 1;
  52. matrix1._type = MatrixTypes.values[typeIdx];
  53. //*((int*)&matrix1._type) |= 1;
  54. }
  55. } else if (types == MatrixTypes.translation) {
  56. double num2 = matrix1._offsetX;
  57. double num3 = matrix1._offsetY;
  58. matrix1 = matrix2;
  59. matrix1._offsetX =
  60. ((num2 * matrix2._m11) + (num3 * matrix2._m21)) + matrix2._offsetX;
  61. matrix1._offsetY =
  62. ((num2 * matrix2._m12) + (num3 * matrix2._m22)) + matrix2._offsetY;
  63. if (types2 == MatrixTypes.unknown) {
  64. matrix1._type = MatrixTypes.unknown;
  65. } else {
  66. matrix1._type = MatrixTypes.values[
  67. MatrixTypes.scaling.index | MatrixTypes.translation.index];
  68. }
  69. } else {
  70. switch ((((types.index) << 4) | types2.index)) {
  71. case 0x22:
  72. matrix1._m11 *= matrix2._m11;
  73. matrix1._m22 *= matrix2._m22;
  74. return reutrnFn();
  75. case 0x23:
  76. matrix1._m11 *= matrix2._m11;
  77. matrix1._m22 *= matrix2._m22;
  78. matrix1._offsetX = matrix2._offsetX;
  79. matrix1._offsetY = matrix2._offsetY;
  80. matrix1._type = MatrixTypes.values[
  81. MatrixTypes.scaling.index | MatrixTypes.translation.index];
  82. return reutrnFn();
  83. case 0x24:
  84. case 0x34:
  85. case 0x42:
  86. case 0x43:
  87. case 0x44:
  88. matrix1 = DMatrix.c(
  89. (matrix1._m11 * matrix2._m11) + (matrix1._m12 * matrix2._m21),
  90. (matrix1._m11 * matrix2._m12) + (matrix1._m12 * matrix2._m22),
  91. (matrix1._m21 * matrix2._m11) + (matrix1._m22 * matrix2._m21),
  92. (matrix1._m21 * matrix2._m12) + (matrix1._m22 * matrix2._m22),
  93. ((matrix1._offsetX * matrix2._m11) +
  94. (matrix1._offsetY * matrix2._m21)) +
  95. matrix2._offsetX,
  96. ((matrix1._offsetX * matrix2._m12) +
  97. (matrix1._offsetY * matrix2._m22)) +
  98. matrix2._offsetY);
  99. return reutrnFn();
  100. case 50:
  101. matrix1._m11 *= matrix2._m11;
  102. matrix1._m22 *= matrix2._m22;
  103. matrix1._offsetX *= matrix2._m11;
  104. matrix1._offsetY *= matrix2._m22;
  105. return reutrnFn();
  106. case 0x33:
  107. matrix1._m11 *= matrix2._m11;
  108. matrix1._m22 *= matrix2._m22;
  109. matrix1._offsetX =
  110. (matrix2._m11 * matrix1._offsetX) + matrix2._offsetX;
  111. matrix1._offsetY =
  112. (matrix2._m22 * matrix1._offsetY) + matrix2._offsetY;
  113. return reutrnFn();
  114. }
  115. }
  116. }
  117. return reutrnFn();
  118. }
  119. }
  120. enum MatrixTypes {
  121. identify,
  122. translation,
  123. scaling,
  124. /// 占位,勿用
  125. uselessAndPlaceHolder,
  126. unknown,
  127. }
  128. class DMatrix {
  129. double _m11 = 0.0;
  130. double _m12 = 0.0;
  131. double _m21 = 0.0;
  132. double _m22 = 0.0;
  133. double _offsetX = 0.0;
  134. double _offsetY = 0.0;
  135. MatrixTypes _type = MatrixTypes.identify;
  136. int _padding = 0;
  137. DMatrix();
  138. factory DMatrix.c(
  139. double m11,
  140. double m12,
  141. double m21,
  142. double m22,
  143. double offsetX,
  144. double offsetY,
  145. ) {
  146. final m = DMatrix();
  147. m._m11 = m11;
  148. m._m12 = m12;
  149. m._m21 = m21;
  150. m._m22 = m22;
  151. m._offsetX = offsetX;
  152. m._offsetY = offsetY;
  153. m._type = MatrixTypes.unknown;
  154. m._padding = 0;
  155. _deriveMatrixType(m);
  156. return m;
  157. }
  158. double get determinant {
  159. if (_type == MatrixTypes.identify || _type == MatrixTypes.translation) {
  160. return 1.0;
  161. }
  162. if (_type == MatrixTypes.scaling) return _m11 * _m22;
  163. final calcType = MatrixTypes
  164. .values[MatrixTypes.scaling.index | MatrixTypes.translation.index];
  165. if (_type == calcType) return _m11 * _m22;
  166. return (_m11 * _m22) - (_m12 * _m21);
  167. }
  168. void translate(double offsetX, double offsetY) {
  169. if (_type == MatrixTypes.identify) {
  170. setMatrix(1.0, 0.0, 0.0, 1.0, offsetX, offsetY, MatrixTypes.translation);
  171. } else if (_type == MatrixTypes.unknown) {
  172. _offsetX += offsetX;
  173. _offsetY += offsetY;
  174. } else {
  175. _offsetX += offsetX;
  176. _offsetY += offsetY;
  177. var typeIdx = _type.index;
  178. typeIdx |= MatrixTypes.translation.index;
  179. _type = MatrixTypes.values[typeIdx];
  180. }
  181. }
  182. void setMatrix(
  183. double m11,
  184. double m12,
  185. double m21,
  186. double m22,
  187. double offsetX,
  188. double offsetY,
  189. MatrixTypes type,
  190. ) {
  191. _m11 = m11;
  192. _m12 = m12;
  193. _m21 = m21;
  194. _m22 = m22;
  195. _offsetX = offsetX;
  196. _offsetY = offsetY;
  197. _type = type;
  198. }
  199. void skew(double skewX, double skewY) {
  200. skewX = skewX % 360.0;
  201. skewY = skewY % 360.0;
  202. final newInstance = this *
  203. createSkewRadians(
  204. skewX * 0.017453292519943295, skewY * 0.017453292519943295);
  205. cover(newInstance);
  206. }
  207. Tuple<double, double> multiplyPoint(double x, double y) {
  208. double nx = x, ny = y;
  209. // ignore: prefer_function_declarations_over_variables
  210. final rstFn = () => Tuple(nx, ny);
  211. if (_type.index ==
  212. MatrixTypes.scaling.index | MatrixTypes.translation.index) {
  213. nx *= _m11;
  214. nx += _offsetX;
  215. ny *= _m22;
  216. ny += _offsetY;
  217. return rstFn();
  218. }
  219. switch (_type) {
  220. case MatrixTypes.identify:
  221. return rstFn();
  222. case MatrixTypes.translation:
  223. x += _offsetX;
  224. y += _offsetY;
  225. return rstFn();
  226. case MatrixTypes.scaling:
  227. x *= _m11;
  228. y *= _m22;
  229. return rstFn();
  230. case MatrixTypes.uselessAndPlaceHolder:
  231. case MatrixTypes.unknown:
  232. break;
  233. }
  234. double num = (ny * _m21) + _offsetX;
  235. double num2 = (nx * _m12) + _offsetY;
  236. nx *= _m11;
  237. nx += num;
  238. ny *= _m22;
  239. ny += num2;
  240. return rstFn();
  241. }
  242. DPoint transform(DPoint point) {
  243. final t = multiplyPoint(point.x, point.y);
  244. return DPoint(t.item1, t.item2);
  245. }
  246. void cover(DMatrix other) {
  247. setMatrix(
  248. other._m11,
  249. other._m12,
  250. other._m21,
  251. other._m22,
  252. other._offsetX,
  253. other._offsetY,
  254. other._type,
  255. );
  256. _padding = other._padding;
  257. }
  258. DMatrix copy() {
  259. final cp = DMatrix();
  260. cp.cover(this);
  261. return cp;
  262. }
  263. void invert() {
  264. if (determinant.abs() < 2.2204460492503131E-15) {
  265. throw Exception("Transform_NotInvertible");
  266. }
  267. final mixType = MatrixTypes
  268. .values[MatrixTypes.scaling.index | MatrixTypes.translation.index];
  269. if (_type == mixType) {
  270. _m11 = 1.0 / _m11;
  271. _m22 = 1.0 / _m22;
  272. _offsetX = -_offsetX * _m11;
  273. _offsetY = -_offsetY * _m22;
  274. return;
  275. }
  276. switch (_type) {
  277. case MatrixTypes.identify:
  278. break;
  279. case MatrixTypes.translation:
  280. _offsetX = -_offsetX;
  281. _offsetY = -_offsetY;
  282. return;
  283. case MatrixTypes.scaling:
  284. _m11 = 1.0 / _m11;
  285. _m22 = 1.0 / _m22;
  286. return;
  287. default:
  288. {
  289. double num2 = 1.0 / determinant;
  290. setMatrix(
  291. _m22 * num2,
  292. -_m12 * num2,
  293. -_m21 * num2,
  294. _m11 * num2,
  295. ((_m21 * _offsetY) - (_offsetX * _m22)) * num2,
  296. ((_offsetX * _m12) - (_m11 * _offsetY)) * num2,
  297. MatrixTypes.unknown);
  298. break;
  299. }
  300. }
  301. }
  302. DMatrix operator *(DMatrix other) {
  303. final result = MatrixUtil.multiplyMatrix(this, other);
  304. return result.first;
  305. }
  306. static DMatrix createSkewRadians(double skewX, double skewY) {
  307. DMatrix matrix = DMatrix();
  308. matrix.setMatrix(1.0, math.tan(skewY), math.tan(skewX), 1.0, 0.0, 0.0,
  309. MatrixTypes.unknown);
  310. return matrix;
  311. }
  312. static void _deriveMatrixType(DMatrix matrix) {
  313. matrix._type = MatrixTypes.identify;
  314. if ((matrix._m21 != 0.0) || (matrix._m12 != 0.0)) {
  315. matrix._type = MatrixTypes.unknown;
  316. } else {
  317. if ((matrix._m11 != 1.0) || (matrix._m22 != 1.0)) {
  318. matrix._type = MatrixTypes.scaling;
  319. }
  320. if ((matrix._offsetX != 0.0) || (matrix._offsetY != 0.0)) {
  321. var typeIdx = matrix._type.index;
  322. typeIdx |= MatrixTypes.translation.index;
  323. matrix._type = MatrixTypes.values[typeIdx];
  324. }
  325. if ((matrix._type.index &
  326. (MatrixTypes.scaling.index | MatrixTypes.translation.index)) ==
  327. MatrixTypes.identify.index) {
  328. matrix._type = MatrixTypes.identify;
  329. }
  330. }
  331. }
  332. }
  333. class DSkewTransform {
  334. // ignore: prefer_final_fields
  335. DMatrix _matrix = DMatrix();
  336. DSkewTransform();
  337. factory DSkewTransform.withAngle(
  338. double angleX,
  339. double angleY,
  340. double centerX,
  341. double centerY,
  342. ) {
  343. final st = DSkewTransform();
  344. bool flag = (centerX != 0.0) || !(centerY == 0.0);
  345. if (flag) {
  346. st._matrix.translate(-centerX, -centerY);
  347. }
  348. st._matrix.skew(angleX, angleY);
  349. if (flag) {
  350. st._matrix.translate(centerX, centerY);
  351. }
  352. return st;
  353. }
  354. factory DSkewTransform.withMatrix(DMatrix matrix) {
  355. final st = DSkewTransform();
  356. st._matrix = matrix;
  357. return st;
  358. }
  359. DSkewTransform get inverse {
  360. final inversedMatrix = _matrix.copy()..invert();
  361. final st = DSkewTransform.withMatrix(inversedMatrix);
  362. return st;
  363. }
  364. DPoint transform(DPoint point) {
  365. return _matrix.transform(point);
  366. }
  367. }
  368. class DPoint extends Point<double> {
  369. const DPoint(double x, double y) : super(x, y);
  370. factory DPoint.fromlPoint(Point<double> point) {
  371. return DPoint(point.x, point.y);
  372. }
  373. factory DPoint.fromOffset(Offset offset) {
  374. return DPoint(offset.dx, offset.dy);
  375. }
  376. static const zero = DPoint(0, 0);
  377. bool operator <(DPoint other) => magnitude < other.magnitude;
  378. bool operator <=(DPoint other) => magnitude <= other.magnitude;
  379. bool operator >(DPoint other) => magnitude > other.magnitude;
  380. bool operator >=(DPoint other) => magnitude >= other.magnitude;
  381. }
  382. class VidController extends GetxController {
  383. // ignore: constant_identifier_names
  384. static const InvalidPoint = DPoint(0, 0);
  385. final _currentIndex = 0.obs;
  386. final Rx<VidUsImageData?> _vidData = Rx(null);
  387. VidUsImageData get vidData => _vidData.value!;
  388. int get currentIndex => _currentIndex.value;
  389. VidUsImage get currentFrame => vidData.getImage(currentIndex);
  390. bool get loaded => _vidData.value != null;
  391. DSkewTransform? _logicalToPhysicalConvert;
  392. final _points = <DPoint>[].obs;
  393. List<DPoint> get points => _points.toList();
  394. double width = 0.0;
  395. double height = 0.0;
  396. final _cursorPoint = Offset.zero.obs;
  397. Offset get cursorPoint => _cursorPoint.value;
  398. final processor = BrightnessProcessor();
  399. final _brightness = 0.obs;
  400. int get brightness => _brightness.value;
  401. ui.Image? image;
  402. Future<void> codecImage([VidUsImage? frame]) async {
  403. image = await decodeImageFromList((frame ?? currentFrame).imageData);
  404. }
  405. @override
  406. void onReady() {
  407. super.onReady();
  408. _loadData();
  409. processor.propertyChanged.add(onProcessorPropertyChanged);
  410. }
  411. @override
  412. void onClose() {
  413. processor.propertyChanged.remove(onProcessorPropertyChanged);
  414. super.onClose();
  415. }
  416. onProcessorPropertyChanged(Object sender, void e) async {
  417. _brightness.value = processor.brightness;
  418. codecImage();
  419. // if (processor.changed) {
  420. // var image = await decodeImageFromList(currentFrame.imageData);
  421. // var data =
  422. // (await image.toByteData(format: ui.ImageByteFormat.rawStraightRgba))!
  423. // .buffer
  424. // .asUint8List();
  425. // frameImage = processor.process(data);
  426. // } else {
  427. // frameImage = currentFrame.imageData;
  428. // }
  429. }
  430. void _loadVisual(VidUsImage frame) {
  431. final visual = frame.visuals.first;
  432. if (visual.visualType == VidUsVisualType.V2D) {
  433. final v2dv = visual as VidUs2DVisual;
  434. final physicalCoordinate =
  435. v2dv.physicalCoordinates[VidUsVisualAreaType.Tissue]
  436. as VidUsLinearTissuePhysicalCoordinate;
  437. _logicalToPhysicalConvert = DSkewTransform.withAngle(
  438. physicalCoordinate.steer,
  439. 0,
  440. 0,
  441. (physicalCoordinate.depthEnd - physicalCoordinate.depthStart) / 2,
  442. ).inverse;
  443. }
  444. clacSize(frame);
  445. }
  446. Future<void> _loadData() async {
  447. final byteData = await rootBundle.load("assets/default.VID");
  448. final bytes = byteData.buffer.asUint8List();
  449. final data = VidUsImageData(bytes);
  450. final firstFrame = data.getImage(0);
  451. _loadVisual(firstFrame);
  452. await codecImage(firstFrame);
  453. // loaded!
  454. _vidData.value = data;
  455. }
  456. DPoint convertPoint(DPoint point) {
  457. if (_logicalToPhysicalConvert != null) {
  458. return _logicalToPhysicalConvert!.transform(point);
  459. }
  460. // TODO: log warn
  461. print('Log_warn - ${DateTime.now()}: Converter not ready.');
  462. return InvalidPoint;
  463. }
  464. void recordPoint(Point<double> point) {
  465. _points.add(DPoint.fromlPoint(point));
  466. }
  467. void clearPoints() => _points.value = [];
  468. void finishDraw() {
  469. if (points.length == 2) {
  470. final p1 = convertPoint(points[0]);
  471. final p2 = convertPoint(points[1]);
  472. final distance = (p2 - p1).magnitude;
  473. print("Cale distance: $distance");
  474. }
  475. }
  476. void clacSize(VidUsImage frame) {
  477. final size = Get.size;
  478. width = frame.width.toDouble();
  479. height = frame.height.toDouble();
  480. if (size.width < width || size.height < height) {
  481. final wR = size.width / width;
  482. final hR = size.height / height;
  483. if (wR > hR) {
  484. height = size.height;
  485. width = size.width * hR;
  486. } else {
  487. height = size.height * wR;
  488. width = size.width;
  489. }
  490. }
  491. }
  492. void onCursorOffsetUpdate(Offset offset) {
  493. _cursorPoint.value = offset;
  494. }
  495. }
  496. class _MyPainter extends CustomPainter {
  497. _MyPainter(this.image);
  498. final ui.Image image;
  499. // ignore: prefer_final_fields
  500. ui.Paint _paint = ui.Paint()..isAntiAlias = true;
  501. @override
  502. void paint(ui.Canvas canvas, ui.Size size) {
  503. // _paint.colorFilter = const ui.ColorFilter.matrix(<double>[
  504. // 1, 0, 0, 0, 220, //
  505. // 0, 1, 0, 0, 220, //
  506. // 0, 0, 1, 0, 220, //
  507. // 0, 0, 0, 1, 0, //
  508. // ]);
  509. _paint.colorFilter = const ui.ColorFilter.matrix(<double>[
  510. 1, 0, 0, 0, 220, //
  511. 0, 1, 0, 0, 220, //
  512. 0, 0, 1, 0, 220, //
  513. 0, 0, 0, 1, 0, //
  514. ]);
  515. final centerW = size.width / 2;
  516. final centerH = size.height / 2;
  517. canvas.translate(centerW, centerH);
  518. final offset = ui.Offset(-centerW, -centerH);
  519. canvas.drawImage(image, offset, _paint);
  520. }
  521. @override
  522. bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
  523. }
  524. class VidMeasurePlayer extends StatelessWidget {
  525. VidMeasurePlayer({Key? key}) : super(key: key);
  526. final c = Get.put(VidController());
  527. @override
  528. Widget build(BuildContext context) {
  529. final size = MediaQuery.of(context).size;
  530. final stack = Stack(
  531. children: [
  532. Obx(() {
  533. if (c.loaded && c.image != null) {
  534. if (c.brightness > 255) {
  535. print('object');
  536. }
  537. return RepaintBoundary(
  538. child: CustomPaint(
  539. // size: ui.Size(c.width / 2, c.height / 2),
  540. painter: _MyPainter(c.image!),
  541. ),
  542. );
  543. // return SizedBox(
  544. // width: c.width,
  545. // height: c.height,
  546. // child: RepaintBoundary(
  547. // child: CustomPaint(
  548. // painter: _MyPainter(c.image!),
  549. // ),
  550. // ),
  551. // );
  552. // return Image.memory(c.frameImage!);
  553. }
  554. return Container();
  555. }),
  556. Obx(() {
  557. if (c.loaded) {
  558. return DrawRecord(
  559. width: c.width,
  560. height: c.height,
  561. );
  562. }
  563. return Container();
  564. }),
  565. Obx(() {
  566. if (c.loaded) {
  567. return Positioned(
  568. child: const Icon(
  569. Icons.add,
  570. color: Colors.amber,
  571. size: 28,
  572. ),
  573. top: c.cursorPoint.dy - 14,
  574. left: c.cursorPoint.dx - 14,
  575. );
  576. }
  577. return Container();
  578. }),
  579. Obx(() {
  580. if (c.loaded) {
  581. return _VidMeasureDrawBoard(
  582. width: c.width,
  583. height: c.height,
  584. );
  585. }
  586. return Container();
  587. }),
  588. Positioned(
  589. top: 20,
  590. right: 40,
  591. child: Container(
  592. color: Colors.white,
  593. height: 50,
  594. width: 100,
  595. child: Row(
  596. mainAxisAlignment: MainAxisAlignment.center,
  597. children: [
  598. IconButton(
  599. onPressed: () {
  600. c.processor.brightness -= 50;
  601. },
  602. icon: Icon(Icons.remove),
  603. ),
  604. IconButton(
  605. onPressed: () {
  606. c.processor.brightness += 50;
  607. },
  608. icon: Icon(Icons.add),
  609. ),
  610. ],
  611. ),
  612. ),
  613. )
  614. ],
  615. );
  616. return Material(
  617. color: Colors.green,
  618. child: stack,
  619. );
  620. }
  621. }
  622. class _DrawBoardController extends GetxController {
  623. _DrawBoardController(this.size);
  624. final Size size;
  625. final _vidController = Get.find<VidController>();
  626. late final _regionMax = DPoint(size.width, size.height);
  627. DPoint? _lastPoint;
  628. DPoint? _lockPoint;
  629. final _active = false.obs;
  630. bool get active => _active.value;
  631. void onClick(DPoint point) {
  632. print(point);
  633. if (active) {
  634. _active.value = false;
  635. _vidController.clearPoints();
  636. _vidController.recordPoint(_lockPoint!);
  637. _vidController.recordPoint(point);
  638. _vidController.finishDraw();
  639. print('logic d: ${(_lockPoint! - point).magnitude}');
  640. } else {
  641. _active.value = true;
  642. _lockPoint = point;
  643. }
  644. }
  645. void onPointUpdate(DPoint point) {
  646. if (point < DPoint.zero) {
  647. if (_lastPoint == DPoint.zero) {
  648. return;
  649. }
  650. point = DPoint.zero;
  651. } else if (point > _regionMax) {
  652. if (_lastPoint == _regionMax) {
  653. return;
  654. }
  655. point = _regionMax;
  656. }
  657. _lastPoint = point;
  658. _vidController.onCursorOffsetUpdate(Offset(point.x, point.y));
  659. if (active) {
  660. print('update:$point');
  661. }
  662. }
  663. }
  664. class _VidMeasureDrawBoard extends StatelessWidget {
  665. _VidMeasureDrawBoard({required this.width, required this.height});
  666. final double width;
  667. final double height;
  668. late final c = Get.put(_DrawBoardController(Size(width, height)));
  669. @override
  670. Widget build(BuildContext context) {
  671. return GestureDetector(
  672. onTapDown: (details) {
  673. c.onClick(DPoint.fromOffset(details.localPosition));
  674. },
  675. onPanUpdate: (details) {
  676. // print('onPanUpdate:${details.localPosition}');
  677. },
  678. child: MouseRegion(
  679. cursor: SystemMouseCursors.none,
  680. onHover: (event) {
  681. c.onPointUpdate(DPoint.fromOffset(event.localPosition));
  682. },
  683. child: SizedBox(width: width, height: height),
  684. ),
  685. );
  686. }
  687. }
  688. class VidPage extends StatelessWidget {
  689. const VidPage({Key? key}) : super(key: key);
  690. @override
  691. Widget build(BuildContext context) {
  692. return VidMeasurePlayer();
  693. }
  694. }