Home > Back-end >  FMX: Strange glitch with TCanvas.DrawPath. Why?
FMX: Strange glitch with TCanvas.DrawPath. Why?

Time:03-02

I draw a path consisting of 2 lines going up and then back down to the same spot, or almost the same spot, but the first line is drawn too high. If I then draw the same lines using DrawLine I don't see the issue. Why is this happening?

Below is an example. Just drop a 400x400 TImage on a blank multiplatform form. The code draws 2 red paths, one with close to a 180 degree angle between the lines and one with less of an angle. The same lines are then drawn using DrawLine in blue. If the DrawPath function works correctly then the blue lines should completely cover the red lines, but they don't. In this example with a scale of 1.5 the path extends 7 pixels too high for the first path. The extent of the error reduces as the lines get further apart. The issue still happens with a scale of 1, but is less obvious.

procedure TForm1.FormActivate(Sender: TObject);
var
  LPath1, LPath2 : TPathData;
  i : Integer;
begin
  // A path of 2 lines going up and then back down to almost the same spot
  LPath1 := TPathData.Create;
  LPath1.MoveTo(PointF(100,200));
  LPath1.LineTo(PointF(100,50 ));
  LPath1.LineTo(PointF(105,200));
  // A path of 2 lines going up and then back down at a wider angle
  LPath2 := TPathData.Create;
  LPath2.MoveTo(PointF(200,200));
  LPath2.LineTo(PointF(200,50 ));
  LPath2.LineTo(PointF(260,200));
  Image1.Bitmap.BitmapScale := 1.5; // The issue shows up more at larger scales
  Image1.Bitmap.SetSize(Trunc(Image1.Width), Trunc(Image1.Height));
  with Image1.Bitmap.Canvas do if BeginScene then begin
    Clear(TAlphaColorRec.White);

    // Draw the paths using DrawPath in red
    Stroke.Color := TAlphaColorRec.Red;
    Stroke.Thickness := 1;
    DrawPath(LPath1, 1);
    DrawPath(LPath2, 1);

    // Draw the paths using DrawLine in blue over the top
    // The red lines should be completely hidden under the blue
    Stroke.Color := TAlphaColorRec.Blue;
    for i := 1 to LPath1.Count - 1 do
      DrawLine(LPath1.Points[i-1].Point, LPath1.Points[i].Point, 1);
    for i := 1 to LPath2.Count - 1 do
      DrawLine(LPath2.Points[i-1].Point, LPath2.Points[i].Point, 1);

    EndScene;
  end;
  LPath1.Free;
  LPath2.Free;

  Image1.Bitmap.SaveToFile('test.png');
end;

Result of the code when run in Windows 10. I'm using Delphi 11, but the same issue happens with Delphi 10. I've tried switching GPU but the same issue occurs.

enter image description here

Enlarged view:

enter image description here

CodePudding user response:

This is because by default TPath is making smooth transitions between different path segments. I'm guessing it might be using Quadratic interpolation for making these smooth transitions.

Yes making smooth transition between two lines doesn't seem logical but it looks this is how it is implemented.

Now you can avoid this by telling the TPath that your two lines are not connected and thus should be treated as two separate lines even thou in reality they are connected. And you can do this by simply calling Path.MoveTo which is intended to shift position so you can create another unconnected line that dos not continue from your last path point.

Here is how modified code for your first sharp cornered line would look like: NOTE that I'm specifying the exact same position for MoveTo command that was used for rendering of previous path line since you don't want the new line to start at new position.

// A path of 2 lines going up and then back down to almost the same spot
  LPath1 := TPathData.Create;
  LPath1.MoveTo(PointF(100,200));
  LPath1.LineTo(PointF(100,50 ));
  //Add move to command to prevent Path from trying to make smooth transitions between two lines
  LPath1.MoveTo(PointF(100,50));
  LPath1.LineTo(PointF(105,200));
  • Related