Einzelnen Beitrag anzeigen

QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
1.944 Beiträge
 
Delphi 12 Athens
 
#3

AW: FMX TPath für SVG Patchen

  Alt 14. Mär 2023, 09:47
Es gibt FMX.Graphics.TPathData.QuadCurveTo(const ControlPoint, EndPoint: TPointF);
Wird irgendwie nur nicht verwendet.

Die sieht so aus für 'Q':
Delphi-Quellcode:
procedure TPathData.QuadCurveTo(const ControlPoint, EndPoint: TPointF);
const
  OneThird = 1 / 3;
  TwoThirds = 2 / 3;
var
  LP, CP1, CP2: TPointF;
begin
  LP := LastPoint;
  CP1.X := OneThird * LP.X + TwoThirds * ControlPoint.X;
  CP1.Y := OneThird * LP.Y + TwoThirds * ControlPoint.Y;
  CP2.X := TwoThirds * ControlPoint.X + OneThird * EndPoint.X;
  CP2.Y := TwoThirds * ControlPoint.Y + OneThird * EndPoint.Y;
  CurveTo(CP1, CP2, EndPoint);
end;
Ich habe dann mal darauf aufbauend folgende weitere methoden "abgeleitet":

Für 'q':
Delphi-Quellcode:
procedure TPathData.QuadCurveToRel(const ControlPoint, EndPoint: TPointF);
var
  LP: TPointF;
begin
  LP := LastPoint;
  QuadCurveTo(LP+ControlPoint,LP+EndPoint);
end;
für 'T':
Delphi-Quellcode:
procedure TPathData.SmoothQuadCurveTo(const EndPoint: TPointF);
var
  ControlPoint1: TPointF;
begin
  if Count > 2 then
    ControlPoint1 := LastPoint + (LastPoint - FPathData[FPathData.Count - 2].Point)
  else
    ControlPoint1 := LastPoint;
  QuadCurveTo(ControlPoint1, EndPoint);
end;
für 't':
Delphi-Quellcode:
procedure TPathData.SmoothQuadCurveToRel(const EndPoint: TPointF);
var
  ControlPoint1: TPointF;
begin
  if Count > 2 then
    ControlPoint1 := LastPoint + (LastPoint - FPathData[FPathData.Count - 2].Point)
  else
    ControlPoint1 := LastPoint;
  QuadCurveToRel(ControlPoint1, EndPoint);
end;

Und dann entsprechend TPathData.SetPathString gepatcht
Delphi-Quellcode:
procedure TPathData.SetPathString(const Value: string);
var
  Builder, TokenBuilder: TStringBuilder;
  PathString, Tokens: string;
  Radius, CurvePoint1, CurvePoint2, TempPoint: TPointF;
  Large, Sweet: Boolean;
  Pos, I, LastLength: Integer;
  Angle: Single;
  Token: Char;
begin
  Builder := TStringBuilder.Create;
  TokenBuilder := TStringBuilder.Create;
  try
    for I := 0 to Value.Length - 1 do
    begin
      if Value.Chars[I].IsInArray([#9, #10, #13]) then
        Builder.Append(' ')
      else
        Builder.Append(Value.Chars[I]);
    end;
    PathString := Builder.ToString;
    FPathData.Clear;
    Pos := 0;
    LastLength := -1;
    while (Builder.Length > Pos) and (LastLength <> Pos) do
    begin
      LastLength := Pos;
      Tokens := GetTokensFromString(PathString, Pos);
      TokenBuilder.Clear;
      TokenBuilder.Append(Tokens);
      while TokenBuilder.Length > 0 do
      begin
        Token := TokenBuilder.Chars[0];
        TokenBuilder.Remove(0, 1);
        case Token of
          'z', 'Z':
            ClosePath;
          'M':
            begin
              MoveTo(GetPointFromString(PathString, Pos));
              while HasRelativeOffset(PathString, Pos) do
                LineTo(GetPointFromString(PathString, Pos));
            end;
          'm':
            begin
              MoveToRel(GetPointFromString(PathString, Pos));
              while HasRelativeOffset(PathString, Pos) do
                LineToRel(GetPointFromString(PathString, Pos));
            end;
          'L':
            begin
              LineTo(GetPointFromString(PathString, Pos));
              while HasRelativeOffset(PathString, Pos) do
                LineTo(GetPointFromString(PathString, Pos));
            end;
          'l':
            begin
              LineToRel(GetPointFromString(PathString, Pos));
              while HasRelativeOffset(PathString, Pos) do
                LineToRel(GetPointFromString(PathString, Pos));
            end;
          'C':
            begin
              CurvePoint1 := GetPointFromString(PathString, Pos);
              CurvePoint2 := GetPointFromString(PathString, Pos);
              CurveTo(CurvePoint1, CurvePoint2, GetPointFromString(PathString, Pos));
              while HasRelativeOffset(PathString, Pos) do
              begin
                CurvePoint1 := GetPointFromString(PathString, Pos);
                CurvePoint2 := GetPointFromString(PathString, Pos);
                CurveTo(CurvePoint1, CurvePoint2, GetPointFromString(PathString, Pos));
              end;
            end;
          'c':
            begin
              CurvePoint1 := GetPointFromString(PathString, Pos);
              CurvePoint2 := GetPointFromString(PathString, Pos);
              CurveToRel(CurvePoint1, CurvePoint2, GetPointFromString(PathString, Pos));
              while HasRelativeOffset(PathString, Pos) do
              begin
                CurvePoint1 := GetPointFromString(PathString, Pos);
                CurvePoint2 := GetPointFromString(PathString, Pos);
                CurveToRel(CurvePoint1, CurvePoint2, GetPointFromString(PathString, Pos));
              end;
            end;
          'S':
            begin
              CurvePoint2 := GetPointFromString(PathString, Pos);
              SmoothCurveTo(CurvePoint2, GetPointFromString(PathString, Pos));
              while HasRelativeOffset(PathString, Pos) do
              begin
                CurvePoint2 := GetPointFromString(PathString, Pos);
                SmoothCurveTo(CurvePoint2, GetPointFromString(PathString, Pos));
              end;
            end;
          's':
            begin
              CurvePoint2 := GetPointFromString(PathString, Pos);
              SmoothCurveToRel(CurvePoint2, GetPointFromString(PathString, Pos));
              while HasRelativeOffset(PathString, Pos) do
              begin
                CurvePoint2 := GetPointFromString(PathString, Pos);
                SmoothCurveToRel(CurvePoint2, GetPointFromString(PathString, Pos));
              end;
            end;
          'H':
            HLineTo(StrToFloat(GetNumberFromString(PathString, Pos), USFormatSettings));
          'h':
            HLineToRel(StrToFloat(GetNumberFromString(PathString, Pos), USFormatSettings));
          'V':
            VLineTo(StrToFloat(GetNumberFromString(PathString, Pos), USFormatSettings));
          'v':
            VLineToRel(StrToFloat(GetNumberFromString(PathString, Pos), USFormatSettings));
          'Q': //A.R. //Quadratic Bezier Curve
            Begin
              CurvePoint1 := GetPointFromString(PathString, Pos);
              QuadCurveTo(CurvePoint1, GetPointFromString(PathString, Pos));
              while HasRelativeOffset(PathString, Pos) do
              begin
                CurvePoint1 := GetPointFromString(PathString, Pos);
                QuadCurveTo(CurvePoint1, GetPointFromString(PathString, Pos));
              end;
            End;
          'q': //A.R. //Quadratic Bezier Curve
            begin
              CurvePoint1 := GetPointFromString(PathString, Pos);
              QuadCurveToRel(CurvePoint1, GetPointFromString(PathString, Pos));
              while HasRelativeOffset(PathString, Pos) do
              begin
                CurvePoint1 := GetPointFromString(PathString, Pos);
                QuadCurveToRel(CurvePoint1, GetPointFromString(PathString, Pos));
              end;
            end;
          'T': //A.R. //Smooth Quadratic Bezier Curve
            begin
              SmoothQuadCurveTo(GetPointFromString(PathString, Pos));
              while HasRelativeOffset(PathString, Pos) do
                SmoothQuadCurveTo(GetPointFromString(PathString, Pos));
            end;
          't': //A.R. //Smooth Quadratic Bezier Curve
            Begin
              CurvePoint2 := GetPointFromString(PathString, Pos);
              SmoothCurveToRel(CurvePoint2, CurvePoint2);
              while HasRelativeOffset(PathString, Pos) do
              begin
                CurvePoint2 := GetPointFromString(PathString, Pos);
                SmoothCurveToRel(CurvePoint2, CurvePoint2);
              end;
            End;
          'A', 'a':
            begin
              if Count > 0 then
                CurvePoint1 := FPathData[FPathData.Count - 1].Point
              else
                CurvePoint1 := TPointF.Zero;
              Radius := GetPointFromString(PathString, Pos);
              Angle := StrToFloat(GetNumberFromString(PathString, Pos), USFormatSettings);
              TempPoint := GetPointFromString(PathString, Pos);
              Large := TempPoint.X = 1;
              Sweet := TempPoint.Y = 1;
              CurvePoint2 := GetPointFromString(PathString, Pos);
              if Token = 'athen
                CurvePoint2 := CurvePoint1 + CurvePoint2;
              AddArcSvg(CurvePoint1, Radius, Angle, Large, Sweet, CurvePoint2);
            end;
        end;
      end;
    end;
    DoChanged;
  finally
    TokenBuilder.Free;
    Builder.Free;
  end;
end;
Dann geht das hier
Delphi-Quellcode:
Path2.Data.Data := 'M24,40'+
                     'Q23,40 22.3,39.3'+
                     'Q21.6,38.6 21.6,37.6'+
                     'Q21.6,36.6 22.3,35.9'+
                     'Q23,35.2 24,35.2'+
                     'Q25,35.2 25.7,35.9'+
                     'Q26.4,36.6 26.4,37.6'+
                     'Q26.4,38.6 25.7,39.3'+
                     'Q25,40 24,40'+
                     'Z'+
                     'M24,26.4'+
                     'Q23,26.4 22.3,25.7'+
                     'Q21.6,25 21.6,24'+
                     'Q21.6,23 22.3,22.3'+
                     'Q23,21.6 24,21.6'+
                     'Q25,21.6 25.7,22.3'+
                     'Q26.4,23 26.4,24'+
                     'Q26.4,25 25.7,25.7'+
                     'Q25,26.4 24,26.4'+
                     'Z'+
                     'M24,12.8'+
                     'Q23,12.8 22.3,12.1'+
                     'Q21.6,11.4 21.6,10.4'+
                     'Q21.6,9.4 22.3,8.7'+
                     'Q23,8 24,8'+
                     'Q25,8 25.7,8.7'+
                     'Q26.4,9.4 26.4,10.4'+
                     'Q26.4,11.4 25.7,12.1'+
                     'Q25,12.8 24,12.8'+
                     'Z';
Keine Ahnung wie man macht das es im Objekt Inspector oder zur designzeit schon funktioniert.

Probiert es aus , bitte. Und feedback oder direkt Verbesserungen!
Andreas
Monads? Wtf are Monads?

Geändert von QuickAndDirty (14. Mär 2023 um 10:59 Uhr)
  Mit Zitat antworten Zitat