vid.dart 21 KB

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