pskink / matrix_gesture_detector

A gesture detector mapping translation/rotation/scale gestures to a Matrix4 object.
Other
134 stars 101 forks source link

coordinates by reverse use of matrix to get original value #16

Open meDerekD17 opened 4 years ago

meDerekD17 commented 4 years ago

After scaling and translating, i tap on the screen. I use the values from MatrixDecompose (translation , scale) to go back to the 'real world without translation and scale' coordinates. They value are always off in Y by the same amount. I am fairly sure it is caused by the AppBar distance. When I remove the AppBar values work. My problem is I I am not completely sure what is happening, so I might get it wrong on different devices. Also, I would prefer to be able to use the Appbar. I can not find a solution of finding AppBar height. Any Suggestions? What have others done with this problem?

meDerekD17 commented 4 years ago

But I notice if I do not enlarge the object on the screen (scale = 1.0) there is no problem. This makes me think I do not understand everything. I use decomposeToValues(matrix) to get translation and scale. I use details.globalPosition to get an Offset (localOffset) then to get the real world coordinates I use: Offset baseOffset = (localOffset - matrixValue.translation) / matrixValue.scale;

Venusdjinni commented 1 year ago

Hello, please did you manage to find a solution for this? I am facing the exact same issue

meDerekD17 commented 1 year ago

I will see if I can fine my GitHub account information to sign on to GitHub and go over what was said before.

I did get it to work for what I wanted, and it has worked OK

On Dec 18, 2022, at 7:07 PM, Venusdjinni @.***> wrote:

Hello, please did you manage to find a solution for this? I am facing the exact same issue

— Reply to this email directly, view it on GitHub https://github.com/pskink/matrix_gesture_detector/issues/16#issuecomment-1356897150, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABW7LCK3J2GZM52NLFVSMUDWN6KLRANCNFSM4MNWL57A. You are receiving this because you authored the thread.

meDerekD17 commented 1 year ago

I think the comments above are what I did. I do not do any rotation, but I do allow translation and scale, and it works. I think what I was concerned about is that I did not quite understand everything, and so something might not work with a different device. But it has worked OK. Maybe if you can say what you have written and what problems you have?

Venusdjinni commented 1 year ago

I am building an image editor, and what I want is to convert the transformation of a widget into 'real scale' values. I managed to do it accurately when there is no scale or rotation, but whenever I enable one of them, MatrixGestureDetector.decompose gives me a bad translation offset

meDerekD17 commented 1 year ago

I did not do rotation, but I did get scale and offset (Translate/move of origin) to work. Sometimes knowing that something works does allow solving. It is getting a bit late here.

meDerekD17 commented 1 year ago

In my gesture detector I have:

//GestureDetector activates 3 'handle' methods below to account for screen //scale and translation (not rotation) void _handleScaleStart(ScaleStartDetails details) { //print('scaleStart details: ${details}'); //from MatrixGestureDetector - onScaleStart()to //seems to be when user does initial touch to drag the screen //focal point is where screen touched. Initializes drag/scale for Board screen // widget.scaleTranslateMatrices.translationUpdater.value = details.focalPoint; // widget.scaleTranslateMatrices.scaleUpdater.value = 1.0; //now using singleton class scaleTranslateMatrices.translationUpdater.value = details.focalPoint; scaleTranslateMatrices.scaleUpdater.value = 1.0; setState(() {}); }

void _handleScaleUpdate(ScaleUpdateDetails details) { //uses singleton class if(referencedData.bOneOfBeginnerHelpsAreShowing) return; scaleTranslateMatrices.translationDeltaMatrix = Matrix4.identity(); scaleTranslateMatrices.scaleDeltaMatrix = Matrix4.identity();

Offset translationDelta = scaleTranslateMatrices.translationUpdater
    .update(details.focalPoint);

//attempt draw 'real' top Left - works for translates & practical zooms
referencedData.osUntransformedTopLeft -=
    translationDelta; //works for translate

scaleTranslateMatrices.translationDeltaMatrix =
    scaleTranslateMatrices.translate(translationDelta);
scaleTranslateMatrices.matrix =
    scaleTranslateMatrices.translationDeltaMatrix *
        scaleTranslateMatrices.matrix; //problem

Offset focalPoint;
RenderBox renderBox = context.findRenderObject();
focalPoint = renderBox.globalToLocal(details.focalPoint);

if (details.scale != 1.0) {
  double scaleDelta =
  scaleTranslateMatrices.scaleUpdater.update(details.scale);

  scaleTranslateMatrices.scaleDeltaMatrix =
      scaleTranslateMatrices.scale(scaleDelta, focalPoint);
  scaleTranslateMatrices.matrix =
      scaleTranslateMatrices.scaleDeltaMatrix *
          scaleTranslateMatrices.matrix;
}
scaleTranslateMatrices.notifier.value =
    scaleTranslateMatrices.matrix;
setState(() {});

}

void _handleScaleReset() { //double tap causes Game screen to reset to default scale and position scaleTranslateMatrices .resetMatrices(); //reset Matrix4s back to initial values referencedData.osUntransformedTopLeft = Offset(0.0, 0.0); setState(() {}); }

@override Widget build(BuildContext context) { return GestureDetector( ....... I think any functions called are in the original library. I could have another look tomorrow if you have further questions

Venusdjinni commented 1 year ago

Thank you. I will have a look at it tomorrow, it's pretty late here too

Venusdjinni commented 1 year ago

Okay I see that you managed the scale using the focal point. Can you share the implementation of scaleTranslateMatrices's class?

meDerekD17 commented 1 year ago

I am not at my computer now, but that class is probably in the original code of the package. I will have a look in a few minutes

Sent from my iPhone

On Dec 19, 2022, at 7:56 AM, Venusdjinni @.***> wrote:

Okay I see that you managed the scale using the focal point. Can you share the implementation of scaleTranslateMatrices's class?

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.

meDerekD17 commented 1 year ago

I have to go to do something with snow. But I have a file named: matrices_classes.dart. It may be that the original has changed since a couple of years ago. I can see a lot of the functions match, but not all: //Classes used in matrix manipulation for scale and translation(offsets) //uses features and code of MatrixGestureDetector - But no rotation //from //https://github.com/pskink/matrix_gesture_detector/blob/master/lib/matrix_gesture_detector.dart

import 'package:flutter/material.dart';

//based on Matrix Gesture Detector // From: https://github.com/pskink/matrix_gesture_detector

class MatrixDecomposedValues { /// Translation, in most cases useful only for matrices that are nothing but /// a translation (no scale and no rotation). final Offset translation;

/// Scaling factor. final double scale;

//2022Aug1 - removed rotation, was not used anyway /// Rotation in radians, (-pi..pi) range. //final double rotation; //But we don't include rotation

MatrixDecomposedValues(this.translation, this.scale); //, this.rotation);

@override String toString() { return 'MatrixDecomposedValues(translation: $translation, ' + 'scale: ${scale.toStringAsFixed(3)}'; // ', rotation: ${rotation.toStringAsFixed(3)})'; } } //class MatrixDecomposedValues {

//From MatrixGestureDetector //appears to set up a class to hold a value, and return (probably) difference //between old value and new value. //Difference needed as applying to Matrices, and want changes - maybe?? typedef _OnUpdate = T Function(T oldValue, T newValue);

class _ValueUpdater { final _OnUpdate onUpdate; T value;

_ValueUpdater({this.onUpdate});

T update(T newValue) { T updated = onUpdate(value, newValue); value = newValue; return updated; } }

class ScaleTranslateMatrices { //appears to be a Singleton class, with, sort of, passed parameters //that are initialized in constructor ScaleTranslateMatrices._privateConstructor(){ // translationDeltaMatrix = Matrix4.identity(); scaleDeltaMatrix = Matrix4.identity(); matrix = Matrix4.identity(); notifier = ValueNotifier(matrix); }

static final ScaleTranslateMatrices instance = ScaleTranslateMatrices ._privateConstructor();

Matrix4 matrix; ValueNotifier notifier; Matrix4 translationDeltaMatrix; Matrix4 scaleDeltaMatrix;

void resetMatrices() { //go back to default view translationDeltaMatrix = Matrix4.identity(); scaleDeltaMatrix = Matrix4.identity(); matrix = Matrix4.identity(); notifier = ValueNotifier(matrix); //is needed }

// Decomposes [matrix] into [MatrixDecomposedValues.translation], // [MatrixDecomposedValues.scale] and [MatrixDecomposedValues.rotation] // components. static MatrixDecomposedValues decomposeToValues(Matrix4 matrix) { var array = matrix.applyToVector3Array([0, 0, 0, 1, 0, 0]); Offset translation = Offset(array[0], array[1]); Offset delta = Offset(array[3] - array[0], array[4] - array[1]); double scale = delta.distance; double rotation = delta.direction; return MatrixDecomposedValues(translation, scale); //, rotation); }

//Matrix creation from GestureDetector - composed from translation and scale // Compose the matrix from translation, scale. // pass a null to skip any matrix from composition. // If [matrix] is not null the result of the composing will be concatenated // to that [matrix], otherwise the identity matrix will be used. static Matrix4 compose( Matrix4 matrix, Matrix4 translationMatrix, Matrix4 scaleMatrix) { if (matrix == null) matrix = Matrix4.identity(); if (translationMatrix != null) matrix = translationMatrix matrix; if (scaleMatrix != null) matrix = scaleMatrix matrix; return matrix; }

//hold values and differences in values _ValueUpdater translationUpdater = _ValueUpdater( onUpdate: (oldVal, newVal) => newVal - oldVal, );

_ValueUpdater scaleUpdater = _ValueUpdater( onUpdate: (oldVal, newVal) => newVal / oldVal, );

Matrix4 translate(Offset translation) { //was _translate //create the translation matrix from dx,dy translation var dx = translation.dx; var dy = translation.dy; // ..[0] = 1 # x scale // ..[5] = 1 # y scale // ..[10] = 1 # diagonal "one" // ..[12] = dx # x translation // ..[13] = dy # y translation // ..[15] = 1 # diagonal "one" return Matrix4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1); }

Matrix4 scale(double scale, Offset focalPoint) { //was_scale //create scale matrix from scale, and focal point (to be clarified**) var dx = (1 - scale) focalPoint.dx; var dy = (1 - scale) * focalPoint.dy; // ..[0] = scale # x scale // ..[5] = scale # y scale // ..[10] = 1 # diagonal "one" // ..[12] = dx # x translation // ..[13] = dy # y translation // ..[15] = 1 # diagonal "one" return Matrix4(scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1); } } //Singleton class ScaleTranslateMatrices