123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- import 'dart:math';
- import 'dart:math' as math;
- import 'dart:ui' as ui;
- import 'package:fis_vid/processors/processor.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:get/get.dart';
- import 'package:quiver/core.dart';
- import 'package:vid/us/vid_us_2d_visual.dart';
- import 'package:vid/us/vid_us_image.dart';
- import 'package:vid/us/vid_us_image_data.dart';
- import 'package:vid/us/vid_us_physical_coordinate.dart';
- import 'package:vid/us/vid_us_visual_area_type.dart';
- import 'package:vid/us/vid_us_visual_type.dart';
- class Tuple<T1, T2> {
- final T1 item1;
- final T2 item2;
- const Tuple(this.item1, this.item2);
- factory Tuple.fromList(List items) {
- if (items.length != 2) {
- throw ArgumentError(
- "Tuple.fromList: argument `items` must have length 2.");
- }
- return Tuple(items[0] as T1, items[1] as T2);
- }
- List toList() => [item1, item2];
- @override
- String toString() => '[$item1, $item2]';
- @override
- bool operator ==(Object other) =>
- other is Tuple && other.item1 == item1 && other.item2 == item2;
- @override
- int get hashCode => hash2(item1, item2);
- }
- class MatrixUtil {
- static List<DMatrix> multiplyMatrix(DMatrix matrix1, DMatrix matrix2) {
- // ignore: prefer_function_declarations_over_variables
- final reutrnFn = () => [matrix1, matrix2];
- MatrixTypes types = matrix1._type;
- MatrixTypes types2 = matrix2._type;
- if (types2 != MatrixTypes.identify) {
- if (types == MatrixTypes.identify) {
- matrix1 = matrix2;
- } else if (types2 == MatrixTypes.translation) {
- matrix1._offsetX += matrix2._offsetX;
- matrix1._offsetY += matrix2._offsetY;
- if (types != MatrixTypes.unknown) {
- var typeIdx = matrix1._type.index;
- typeIdx |= 1;
- matrix1._type = MatrixTypes.values[typeIdx];
- //*((int*)&matrix1._type) |= 1;
- }
- } else if (types == MatrixTypes.translation) {
- double num2 = matrix1._offsetX;
- double num3 = matrix1._offsetY;
- matrix1 = matrix2;
- matrix1._offsetX =
- ((num2 * matrix2._m11) + (num3 * matrix2._m21)) + matrix2._offsetX;
- matrix1._offsetY =
- ((num2 * matrix2._m12) + (num3 * matrix2._m22)) + matrix2._offsetY;
- if (types2 == MatrixTypes.unknown) {
- matrix1._type = MatrixTypes.unknown;
- } else {
- matrix1._type = MatrixTypes.values[
- MatrixTypes.scaling.index | MatrixTypes.translation.index];
- }
- } else {
- switch ((((types.index) << 4) | types2.index)) {
- case 0x22:
- matrix1._m11 *= matrix2._m11;
- matrix1._m22 *= matrix2._m22;
- return reutrnFn();
- case 0x23:
- matrix1._m11 *= matrix2._m11;
- matrix1._m22 *= matrix2._m22;
- matrix1._offsetX = matrix2._offsetX;
- matrix1._offsetY = matrix2._offsetY;
- matrix1._type = MatrixTypes.values[
- MatrixTypes.scaling.index | MatrixTypes.translation.index];
- return reutrnFn();
- case 0x24:
- case 0x34:
- case 0x42:
- case 0x43:
- case 0x44:
- matrix1 = DMatrix.c(
- (matrix1._m11 * matrix2._m11) + (matrix1._m12 * matrix2._m21),
- (matrix1._m11 * matrix2._m12) + (matrix1._m12 * matrix2._m22),
- (matrix1._m21 * matrix2._m11) + (matrix1._m22 * matrix2._m21),
- (matrix1._m21 * matrix2._m12) + (matrix1._m22 * matrix2._m22),
- ((matrix1._offsetX * matrix2._m11) +
- (matrix1._offsetY * matrix2._m21)) +
- matrix2._offsetX,
- ((matrix1._offsetX * matrix2._m12) +
- (matrix1._offsetY * matrix2._m22)) +
- matrix2._offsetY);
- return reutrnFn();
- case 50:
- matrix1._m11 *= matrix2._m11;
- matrix1._m22 *= matrix2._m22;
- matrix1._offsetX *= matrix2._m11;
- matrix1._offsetY *= matrix2._m22;
- return reutrnFn();
- case 0x33:
- matrix1._m11 *= matrix2._m11;
- matrix1._m22 *= matrix2._m22;
- matrix1._offsetX =
- (matrix2._m11 * matrix1._offsetX) + matrix2._offsetX;
- matrix1._offsetY =
- (matrix2._m22 * matrix1._offsetY) + matrix2._offsetY;
- return reutrnFn();
- }
- }
- }
- return reutrnFn();
- }
- }
- enum MatrixTypes {
- identify,
- translation,
- scaling,
- /// 占位,勿用
- uselessAndPlaceHolder,
- unknown,
- }
- class DMatrix {
- double _m11 = 0.0;
- double _m12 = 0.0;
- double _m21 = 0.0;
- double _m22 = 0.0;
- double _offsetX = 0.0;
- double _offsetY = 0.0;
- MatrixTypes _type = MatrixTypes.identify;
- int _padding = 0;
- DMatrix();
- factory DMatrix.c(
- double m11,
- double m12,
- double m21,
- double m22,
- double offsetX,
- double offsetY,
- ) {
- final m = DMatrix();
- m._m11 = m11;
- m._m12 = m12;
- m._m21 = m21;
- m._m22 = m22;
- m._offsetX = offsetX;
- m._offsetY = offsetY;
- m._type = MatrixTypes.unknown;
- m._padding = 0;
- _deriveMatrixType(m);
- return m;
- }
- double get determinant {
- if (_type == MatrixTypes.identify || _type == MatrixTypes.translation) {
- return 1.0;
- }
- if (_type == MatrixTypes.scaling) return _m11 * _m22;
- final calcType = MatrixTypes
- .values[MatrixTypes.scaling.index | MatrixTypes.translation.index];
- if (_type == calcType) return _m11 * _m22;
- return (_m11 * _m22) - (_m12 * _m21);
- }
- void translate(double offsetX, double offsetY) {
- if (_type == MatrixTypes.identify) {
- setMatrix(1.0, 0.0, 0.0, 1.0, offsetX, offsetY, MatrixTypes.translation);
- } else if (_type == MatrixTypes.unknown) {
- _offsetX += offsetX;
- _offsetY += offsetY;
- } else {
- _offsetX += offsetX;
- _offsetY += offsetY;
- var typeIdx = _type.index;
- typeIdx |= MatrixTypes.translation.index;
- _type = MatrixTypes.values[typeIdx];
- }
- }
- void setMatrix(
- double m11,
- double m12,
- double m21,
- double m22,
- double offsetX,
- double offsetY,
- MatrixTypes type,
- ) {
- _m11 = m11;
- _m12 = m12;
- _m21 = m21;
- _m22 = m22;
- _offsetX = offsetX;
- _offsetY = offsetY;
- _type = type;
- }
- void skew(double skewX, double skewY) {
- skewX = skewX % 360.0;
- skewY = skewY % 360.0;
- final newInstance = this *
- createSkewRadians(
- skewX * 0.017453292519943295, skewY * 0.017453292519943295);
- cover(newInstance);
- }
- Tuple<double, double> multiplyPoint(double x, double y) {
- double nx = x, ny = y;
- // ignore: prefer_function_declarations_over_variables
- final rstFn = () => Tuple(nx, ny);
- if (_type.index ==
- MatrixTypes.scaling.index | MatrixTypes.translation.index) {
- nx *= _m11;
- nx += _offsetX;
- ny *= _m22;
- ny += _offsetY;
- return rstFn();
- }
- switch (_type) {
- case MatrixTypes.identify:
- return rstFn();
- case MatrixTypes.translation:
- x += _offsetX;
- y += _offsetY;
- return rstFn();
- case MatrixTypes.scaling:
- x *= _m11;
- y *= _m22;
- return rstFn();
- case MatrixTypes.uselessAndPlaceHolder:
- case MatrixTypes.unknown:
- break;
- }
- double num = (ny * _m21) + _offsetX;
- double num2 = (nx * _m12) + _offsetY;
- nx *= _m11;
- nx += num;
- ny *= _m22;
- ny += num2;
- return rstFn();
- }
- DPoint transform(DPoint point) {
- final t = multiplyPoint(point.x, point.y);
- return DPoint(t.item1, t.item2);
- }
- void cover(DMatrix other) {
- setMatrix(
- other._m11,
- other._m12,
- other._m21,
- other._m22,
- other._offsetX,
- other._offsetY,
- other._type,
- );
- _padding = other._padding;
- }
- DMatrix copy() {
- final cp = DMatrix();
- cp.cover(this);
- return cp;
- }
- void invert() {
- if (determinant.abs() < 2.2204460492503131E-15) {
- throw Exception("Transform_NotInvertible");
- }
- final mixType = MatrixTypes
- .values[MatrixTypes.scaling.index | MatrixTypes.translation.index];
- if (_type == mixType) {
- _m11 = 1.0 / _m11;
- _m22 = 1.0 / _m22;
- _offsetX = -_offsetX * _m11;
- _offsetY = -_offsetY * _m22;
- return;
- }
- switch (_type) {
- case MatrixTypes.identify:
- break;
- case MatrixTypes.translation:
- _offsetX = -_offsetX;
- _offsetY = -_offsetY;
- return;
- case MatrixTypes.scaling:
- _m11 = 1.0 / _m11;
- _m22 = 1.0 / _m22;
- return;
- default:
- {
- double num2 = 1.0 / determinant;
- setMatrix(
- _m22 * num2,
- -_m12 * num2,
- -_m21 * num2,
- _m11 * num2,
- ((_m21 * _offsetY) - (_offsetX * _m22)) * num2,
- ((_offsetX * _m12) - (_m11 * _offsetY)) * num2,
- MatrixTypes.unknown);
- break;
- }
- }
- }
- DMatrix operator *(DMatrix other) {
- final result = MatrixUtil.multiplyMatrix(this, other);
- return result.first;
- }
- static DMatrix createSkewRadians(double skewX, double skewY) {
- DMatrix matrix = DMatrix();
- matrix.setMatrix(1.0, math.tan(skewY), math.tan(skewX), 1.0, 0.0, 0.0,
- MatrixTypes.unknown);
- return matrix;
- }
- static void _deriveMatrixType(DMatrix matrix) {
- matrix._type = MatrixTypes.identify;
- if ((matrix._m21 != 0.0) || (matrix._m12 != 0.0)) {
- matrix._type = MatrixTypes.unknown;
- } else {
- if ((matrix._m11 != 1.0) || (matrix._m22 != 1.0)) {
- matrix._type = MatrixTypes.scaling;
- }
- if ((matrix._offsetX != 0.0) || (matrix._offsetY != 0.0)) {
- var typeIdx = matrix._type.index;
- typeIdx |= MatrixTypes.translation.index;
- matrix._type = MatrixTypes.values[typeIdx];
- }
- if ((matrix._type.index &
- (MatrixTypes.scaling.index | MatrixTypes.translation.index)) ==
- MatrixTypes.identify.index) {
- matrix._type = MatrixTypes.identify;
- }
- }
- }
- }
- class DSkewTransform {
- // ignore: prefer_final_fields
- DMatrix _matrix = DMatrix();
- DSkewTransform();
- factory DSkewTransform.withAngle(
- double angleX,
- double angleY,
- double centerX,
- double centerY,
- ) {
- final st = DSkewTransform();
- bool flag = (centerX != 0.0) || !(centerY == 0.0);
- if (flag) {
- st._matrix.translate(-centerX, -centerY);
- }
- st._matrix.skew(angleX, angleY);
- if (flag) {
- st._matrix.translate(centerX, centerY);
- }
- return st;
- }
- factory DSkewTransform.withMatrix(DMatrix matrix) {
- final st = DSkewTransform();
- st._matrix = matrix;
- return st;
- }
- DSkewTransform get inverse {
- final inversedMatrix = _matrix.copy()..invert();
- final st = DSkewTransform.withMatrix(inversedMatrix);
- return st;
- }
- DPoint transform(DPoint point) {
- return _matrix.transform(point);
- }
- }
- class DPoint extends Point<double> {
- const DPoint(double x, double y) : super(x, y);
- factory DPoint.fromlPoint(Point<double> point) {
- return DPoint(point.x, point.y);
- }
- factory DPoint.fromOffset(Offset offset) {
- return DPoint(offset.dx, offset.dy);
- }
- static const zero = DPoint(0, 0);
- bool operator <(DPoint other) => magnitude < other.magnitude;
- bool operator <=(DPoint other) => magnitude <= other.magnitude;
- bool operator >(DPoint other) => magnitude > other.magnitude;
- bool operator >=(DPoint other) => magnitude >= other.magnitude;
- }
- class VidController extends GetxController {
- // ignore: constant_identifier_names
- static const InvalidPoint = DPoint(0, 0);
- final _currentIndex = 0.obs;
- final Rx<VidUsImageData?> _vidData = Rx(null);
- VidUsImageData get vidData => _vidData.value!;
- int get currentIndex => _currentIndex.value;
- VidUsImage get currentFrame => vidData.getImage(currentIndex);
- bool get loaded => _vidData.value != null;
- DSkewTransform? _logicalToPhysicalConvert;
- final _points = <DPoint>[].obs;
- List<DPoint> get points => _points.toList();
- double width = 0.0;
- double height = 0.0;
- final _cursorPoint = Offset.zero.obs;
- Offset get cursorPoint => _cursorPoint.value;
- final processor = BrightnessProcessor();
- final _brightness = 0.obs;
- int get brightness => _brightness.value;
- ui.Image? image;
- Future<void> codecImage([VidUsImage? frame]) async {
- image = await decodeImageFromList((frame ?? currentFrame).imageData);
- }
- @override
- void onReady() {
- super.onReady();
- _loadData();
- processor.propertyChanged.add(onProcessorPropertyChanged);
- }
- @override
- void onClose() {
- processor.propertyChanged.remove(onProcessorPropertyChanged);
- super.onClose();
- }
- onProcessorPropertyChanged(Object sender, void e) async {
- _brightness.value = processor.brightness;
- codecImage();
- // if (processor.changed) {
- // var image = await decodeImageFromList(currentFrame.imageData);
- // var data =
- // (await image.toByteData(format: ui.ImageByteFormat.rawStraightRgba))!
- // .buffer
- // .asUint8List();
- // frameImage = processor.process(data);
- // } else {
- // frameImage = currentFrame.imageData;
- // }
- }
- void _loadVisual(VidUsImage frame) {
- final visual = frame.visuals.first;
- if (visual.visualType == VidUsVisualType.V2D) {
- final v2dv = visual as VidUs2DVisual;
- final physicalCoordinate =
- v2dv.physicalCoordinates[VidUsVisualAreaType.Tissue]
- as VidUsLinearTissuePhysicalCoordinate;
- _logicalToPhysicalConvert = DSkewTransform.withAngle(
- physicalCoordinate.steer,
- 0,
- 0,
- (physicalCoordinate.depthEnd - physicalCoordinate.depthStart) / 2,
- ).inverse;
- }
- clacSize(frame);
- }
- Future<void> _loadData() async {
- final byteData = await rootBundle.load("assets/default.VID");
- final bytes = byteData.buffer.asUint8List();
- final data = VidUsImageData(bytes);
- final firstFrame = data.getImage(0);
- _loadVisual(firstFrame);
- await codecImage(firstFrame);
- // loaded!
- _vidData.value = data;
- }
- DPoint convertPoint(DPoint point) {
- if (_logicalToPhysicalConvert != null) {
- return _logicalToPhysicalConvert!.transform(point);
- }
- // TODO: log warn
- print('Log_warn - ${DateTime.now()}: Converter not ready.');
- return InvalidPoint;
- }
- void recordPoint(Point<double> point) {
- _points.add(DPoint.fromlPoint(point));
- }
- void clearPoints() => _points.value = [];
- void finishDraw() {
- if (points.length == 2) {
- final p1 = convertPoint(points[0]);
- final p2 = convertPoint(points[1]);
- final distance = (p2 - p1).magnitude;
- print("Cale distance: $distance");
- }
- }
- void clacSize(VidUsImage frame) {
- final size = Get.size;
- width = frame.width.toDouble();
- height = frame.height.toDouble();
- if (size.width < width || size.height < height) {
- final wR = size.width / width;
- final hR = size.height / height;
- if (wR > hR) {
- height = size.height;
- width = size.width * hR;
- } else {
- height = size.height * wR;
- width = size.width;
- }
- }
- }
- void onCursorOffsetUpdate(Offset offset) {
- _cursorPoint.value = offset;
- }
- }
- class _MyPainter extends CustomPainter {
- _MyPainter(this.image);
- final ui.Image image;
- // ignore: prefer_final_fields
- ui.Paint _paint = ui.Paint()..isAntiAlias = true;
- @override
- void paint(ui.Canvas canvas, ui.Size size) {
- // _paint.colorFilter = const ui.ColorFilter.matrix(<double>[
- // 1, 0, 0, 0, 220, //
- // 0, 1, 0, 0, 220, //
- // 0, 0, 1, 0, 220, //
- // 0, 0, 0, 1, 0, //
- // ]);
- _paint.colorFilter = const ui.ColorFilter.matrix(<double>[
- 1, 0, 0, 0, 220, //
- 0, 1, 0, 0, 220, //
- 0, 0, 1, 0, 220, //
- 0, 0, 0, 1, 0, //
- ]);
- final centerW = size.width / 2;
- final centerH = size.height / 2;
- canvas.translate(centerW, centerH);
- final offset = ui.Offset(-centerW, -centerH);
- canvas.drawImage(image, offset, _paint);
- }
- @override
- bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
- }
- class VidMeasurePlayer extends StatelessWidget {
- VidMeasurePlayer({Key? key}) : super(key: key);
- final c = Get.put(VidController());
- @override
- Widget build(BuildContext context) {
- final size = MediaQuery.of(context).size;
- final stack = Stack(
- children: [
- Obx(() {
- if (c.loaded && c.image != null) {
- if (c.brightness > 255) {
- print('object');
- }
- return RepaintBoundary(
- child: CustomPaint(
- // size: ui.Size(c.width / 2, c.height / 2),
- painter: _MyPainter(c.image!),
- ),
- );
- // return SizedBox(
- // width: c.width,
- // height: c.height,
- // child: RepaintBoundary(
- // child: CustomPaint(
- // painter: _MyPainter(c.image!),
- // ),
- // ),
- // );
- // return Image.memory(c.frameImage!);
- }
- return Container();
- }),
- Obx(() {
- if (c.loaded) {
- return DrawRecord(
- width: c.width,
- height: c.height,
- );
- }
- return Container();
- }),
- Obx(() {
- if (c.loaded) {
- return Positioned(
- child: const Icon(
- Icons.add,
- color: Colors.amber,
- size: 28,
- ),
- top: c.cursorPoint.dy - 14,
- left: c.cursorPoint.dx - 14,
- );
- }
- return Container();
- }),
- Obx(() {
- if (c.loaded) {
- return _VidMeasureDrawBoard(
- width: c.width,
- height: c.height,
- );
- }
- return Container();
- }),
- Positioned(
- top: 20,
- right: 40,
- child: Container(
- color: Colors.white,
- height: 50,
- width: 100,
- child: Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- IconButton(
- onPressed: () {
- c.processor.brightness -= 50;
- },
- icon: const Icon(Icons.remove),
- ),
- IconButton(
- onPressed: () {
- c.processor.brightness += 50;
- },
- icon: const Icon(Icons.add),
- ),
- ],
- ),
- ),
- )
- ],
- );
- return Material(
- color: Colors.green,
- child: stack,
- );
- }
- }
- class _DrawBoardController extends GetxController {
- _DrawBoardController(this.size);
- final Size size;
- final _vidController = Get.find<VidController>();
- late final _regionMax = DPoint(size.width, size.height);
- DPoint? _lastPoint;
- DPoint? _lockPoint;
- final _active = false.obs;
- bool get active => _active.value;
- void onClick(DPoint point) {
- print(point);
- if (active) {
- _active.value = false;
- _vidController.clearPoints();
- _vidController.recordPoint(_lockPoint!);
- _vidController.recordPoint(point);
- _vidController.finishDraw();
- print('logic d: ${(_lockPoint! - point).magnitude}');
- } else {
- _active.value = true;
- _lockPoint = point;
- }
- }
- void onPointUpdate(DPoint point) {
- if (point < DPoint.zero) {
- if (_lastPoint == DPoint.zero) {
- return;
- }
- point = DPoint.zero;
- } else if (point > _regionMax) {
- if (_lastPoint == _regionMax) {
- return;
- }
- point = _regionMax;
- }
- _lastPoint = point;
- _vidController.onCursorOffsetUpdate(Offset(point.x, point.y));
- if (active) {
- print('update:$point');
- }
- }
- }
- class _VidMeasureDrawBoard extends StatelessWidget {
- _VidMeasureDrawBoard({required this.width, required this.height});
- final double width;
- final double height;
- late final c = Get.put(_DrawBoardController(Size(width, height)));
- @override
- Widget build(BuildContext context) {
- return GestureDetector(
- onTapDown: (details) {
- c.onClick(DPoint.fromOffset(details.localPosition));
- },
- onPanUpdate: (details) {
- // print('onPanUpdate:${details.localPosition}');
- },
- child: MouseRegion(
- cursor: SystemMouseCursors.none,
- onHover: (event) {
- c.onPointUpdate(DPoint.fromOffset(event.localPosition));
- },
- child: SizedBox(width: width, height: height),
- ),
- );
- }
- }
- class VidPage extends StatelessWidget {
- const VidPage({Key? key}) : super(key: key);
- @override
- Widget build(BuildContext context) {
- return VidMeasurePlayer();
- }
- }
- class DrawRecord extends StatelessWidget {
- const DrawRecord({
- Key? key,
- required this.width,
- required this.height,
- }) : super(key: key);
- final double width;
- final double height;
- @override
- Widget build(BuildContext context) {
- return RepaintBoundary(
- child: CustomPaint(
- painter: _DrawRecordPainter(),
- ),
- );
- }
- }
- class _DrawRecordPainter extends CustomPainter {
- final pen = Paint()
- ..color = Colors.red
- ..isAntiAlias = true;
- @override
- void paint(Canvas canvas, Size size) {
- print("draw at ${DateTime.now()}");
- canvas.drawLine(
- const Offset(100, 100),
- const Offset(200, 200),
- pen,
- );
- }
- @override
- bool shouldRepaint(covariant CustomPainter oldDelegate) {
- return false;
- }
- }
|