Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Cross-Platform-Entwicklung (https://www.delphipraxis.net/91-cross-platform-entwicklung/)
-   -   iOS Trägheitsberechnung bei Gestures (https://www.delphipraxis.net/177473-traegheitsberechnung-bei-gestures.html)

Union 8. Nov 2013 08:51

Trägheitsberechnung bei Gestures
 
Das Thema betrifft auch Android.

Da in Firemonkey die Trägheit von Bewegungen bei der Verarbeitung von Gesten auf den mobilen Plattformen nicht unterstützt wird, muß man sich das ja zwangsweise selber schreiben. Hat da jemand was Fertiges? Ich habe zwar Ansätze, stoße aber immer wieder auf Sonderfälle.

Verarbeitung im Gesturevent beim Panning:
  • Im gfbegin - Merken der aktuellen Position und Zeit
  • Im gfEnd - Errechnen der Distanz aus der aktuellen und gemerkten Position für jede Achse
  • Errechnen der Geschwindigkeiten aus den Distanzen und der verstrichenen Zeit
  • Bei Überschreiten eines Grenzwertes eine FloatAnimation für jede Achse ausführen mit atOut und itQuadratic
Was mir daran nicht gefällt (bei meinen Prototyp-Versuchen jedenfalls) ist, dass man für das Merken der Werte globale Variablen hat. Spätestens wenn man ZWEI GestureEvents im gleichen Formular verwendet wird das unangenehm.

Darlo 8. Nov 2013 14:06

AW: Trägheitsberechnung bei Gestures
 
Zitat:

Zitat von Union (Beitrag 1235053)
Was mir daran nicht gefällt (bei meinen Prototyp-Versuchen jedenfalls) ist, dass man für das Merken der Werte globale Variablen hat. Spätestens wenn man ZWEI GestureEvents im gleichen Formular verwendet wird das unangenehm.

So habe ich es auch, funktioniert. Wollte zuerst den Tag des Objektes missbrauchen, fand das aber auch nicht schöner....

Union 8. Nov 2013 17:56

AW: Trägheitsberechnung bei Gestures
 
Ich habe das Fehlen der Verarbeitung der Trägheitswerte gemeldet.

So sieht meine OnGesture momentan aus (gezeichnet wird asynchron abhängig von NeedsPaint damit man performant zoomen kann):
Delphi-Quellcode:
public
    StartDistance : integer;
    StartLocation : TPointF;
    StartPos : TPointF;
    LastZoomed : TDateTime;
    LastPanned : TDateTime;
    NeedsPaint : Boolean;
    CursorCircle : TCircle;
end;

procedure TForm1.Layout1Gesture(Sender: TObject;
  const EventInfo: TGestureEventInfo; var Handled: Boolean);
var
  Factor : double;
  NewScale : double;
  Speed   : TPointF;
  Distance : TPointF;
begin
  if EventInfo.GestureID = igiZoom then
  begin
    if TInteractiveGestureFlag.gfBegin in EventInfo.Flags then
       StartDistance := EventInfo.Distance
    else
    begin
      Factor := EventInfo.Distance / StartDistance;
      if (Factor > 0.04) or (Factor < -0.04) then
      begin
        NewScale := Painter.Scale * Factor;
        if NewScale > MaxScale then
          NewScale := MaxScale;
        if (NewScale <= MaxScale) and (NewScale > 0.5) then
        begin
          Painter.Scale := NewScale;
          Imagecontrol1.Scale.X := NewScale/Painter.PaintedScale*Factor;
          Imagecontrol1.Scale.Y := NewScale/Painter.PaintedScale*Factor;
          CursorCircle.Scale.X := Painter.Scale;
          CursorCircle.Scale.Y := Painter.Scale;
          LastZoomed   := Now;
          NeedsPaint := True;
        end;
      end;
      StartDistance := EventInfo.Distance;
    end;
  end
  else
  if Eventinfo.GestureID = igiDoubleTap then
  begin
    ShowMessage(Format('IW: %f BW: %d', [Imagecontrol1.Width, Painter.Bitmap.Width]));
  end
  else
  if EventInfo.GestureID = igiPan then
  begin
    // Um zu verhindern dass beim Beenden einer Zoomoperation die Bewegung des
    // zuletzt angehobenen Fingers als Bewegungswunsch angesehen wird.
    if MilliSecondsBetween(Now, LastZoomed) > 100 then
    begin
      if TInteractiveGestureFlag.gfBegin in EventInfo.Flags then
      begin
         StartLocation := EventInfo.Location;
         StartPos := EventInfo.Location;
         LastPanned := Now;
      end
      else
      if TInteractiveGestureFlag.gfEnd in EventInfo.Flags then
      begin
        Factor := MSecsPerDay*(Now-LastPanned);
        Distance.X := EventInfo.Location.X-StartPos.X;
        Distance.Y := EventInfo.Location.Y-StartPos.Y;
        Speed.X   := Distance.X / Factor;
        Speed.Y   := Distance.Y / Factor;
        AdjustPosition(Speed);
      end
      else
      begin
        ImageControl1.Position.X := ImageControl1.Position.X + (EventInfo.Location.X - StartLocation.X);
        ImageControl1.Position.Y := ImageControl1.Position.Y + (EventInfo.Location.Y - StartLocation.Y);
        Speed.X := 0;
        Speed.Y := 0;
        AdjustPosition(Speed);
        StartLocation := EventInfo.Location;
      end;
    end;
  end;
end;

procedure TForm1.AdjustPosition(ASpeed : TPointF);
begin
  // Trägheit simulieren
  if abs(ASpeed.X) > 1 then
     ImageControl1.AnimateFloat('Position.X', Imagecontrol1.Position.X+50*ASpeed.X, 0.5, TAnimationType.atOut, TInterpolationType.itQuadratic);
  if abs(ASpeed.Y) > 1 then
     ImageControl1.AnimateFloat('Position.Y', Imagecontrol1.Position.Y+50*ASpeed.Y, 0.5, TAnimationType.atOut, TInterpolationType.itQuadratic);

  // Ggf. Bounceback wenn zu nah an den Rand bewegt
  if ImageControl1.Position.X+(Imagecontrol1.Width/2) < 50 then
     ImageControl1.AnimateFloat('Position.X', 100-(Imagecontrol1.Width/2), 0.3)
  else
  if ImageControl1.Position.X > Layout1.Width -50 then
    Imagecontrol1.AnimateFloat('Position.X', Layout1.Width-100, 0.3);

  if ImageControl1.Position.Y+(Imagecontrol1.Height/2) < 50 then
     ImageControl1.AnimateFloat('Position.Y', 100-(Imagecontrol1.Height/2), 0.3)
  else
  if ImageControl1.Position.Y > Layout1.Height -50 then
    Imagecontrol1.AnimateFloat('Position.Y', Layout1.Height-100, 0.3);
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:18 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz