fpvectorial: Implements support for clipping regions, specially for PostScript

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1768 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
sekelsenmat
2011-07-29 11:11:14 +00:00
parent fe2f8d3153
commit d043a4676f
4 changed files with 110 additions and 17 deletions

View File

@ -71,6 +71,8 @@ type
public public
Color: TFPColor; Color: TFPColor;
TranslateX, TranslateY: Double; TranslateX, TranslateY: Double;
ClipPath: TPath;
ClipMode: TvClipMode;
function Duplicate: TGraphicState; function Duplicate: TGraphicState;
end; end;
@ -144,6 +146,7 @@ begin
Result.Color := Color; Result.Color := Color;
Result.TranslateX := TranslateX; Result.TranslateX := TranslateX;
Result.TranslateY := TranslateY; Result.TranslateY := TranslateY;
Result.ClipPath := ClipPath;
end; end;
{ TPSToken } { TPSToken }
@ -1467,6 +1470,7 @@ begin
{$ifdef FPVECTORIALDEBUG_PATHS} {$ifdef FPVECTORIALDEBUG_PATHS}
WriteLn('[TvEPSVectorialReader.ExecutePathConstructionOperator] newpath'); WriteLn('[TvEPSVectorialReader.ExecutePathConstructionOperator] newpath');
{$endif} {$endif}
AData.SetClipPath(CurrentGraphicState.ClipPath, CurrentGraphicState.ClipMode);
AData.EndPath(); AData.EndPath();
AData.StartPath(); AData.StartPath();
@ -1611,6 +1615,10 @@ begin
// – eoclip – Clip using even-odd rule // – eoclip – Clip using even-odd rule
if AToken.StrValue = 'eoclip' then if AToken.StrValue = 'eoclip' then
begin begin
AData.SetPenStyle(psClear);
AData.EndPath();
CurrentGraphicState.ClipPath := AData.GetPath(AData.GetPathCount()-1);
CurrentGraphicState.ClipMode := vcmEvenOddRule;
Exit(True); Exit(True);
end end
end; end;

View File

@ -157,11 +157,15 @@ type
constructor Create; virtual; constructor Create; virtual;
end; end;
TvClipMode = (vcmNonzeroWindingRule, vcmEvenOddRule);
TPath = class(TvEntity) TPath = class(TvEntity)
Len: Integer; Len: Integer;
Points: TPathSegment; // Beginning of the double-linked list Points: TPathSegment; // Beginning of the double-linked list
PointsEnd: TPathSegment; // End of the double-linked list PointsEnd: TPathSegment;// End of the double-linked list
CurPoint: TPathSegment; // Used in PrepareForSequentialReading and Next CurPoint: TPathSegment; // Used in PrepareForSequentialReading and Next
ClipPath: TPath;
ClipMode: TvClipMode;
procedure Assign(ASource: TPath); procedure Assign(ASource: TPath);
procedure PrepareForSequentialReading; procedure PrepareForSequentialReading;
function Next(): TPathSegment; function Next(): TPathSegment;
@ -303,6 +307,7 @@ type
procedure SetPenColor(AColor: TFPColor); procedure SetPenColor(AColor: TFPColor);
procedure SetPenStyle(AStyle: TFPPenStyle); procedure SetPenStyle(AStyle: TFPPenStyle);
procedure SetPenWidth(AWidth: Integer); procedure SetPenWidth(AWidth: Integer);
procedure SetClipPath(AClipPath: TPath; AClipMode: TvClipMode);
procedure EndPath(); procedure EndPath();
procedure AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string); overload; procedure AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string); overload;
procedure AddText(AX, AY, AZ: Double; AStr: utf8string); overload; procedure AddText(AX, AY, AZ: Double; AStr: utf8string); overload;
@ -737,6 +742,13 @@ begin
FTmPPath.Pen.Width := AWidth; FTmPPath.Pen.Width := AWidth;
end; end;
procedure TvVectorialDocument.SetClipPath(AClipPath: TPath;
AClipMode: TvClipMode);
begin
FTmPPath.ClipPath := AClipPath;
FTmPPath.ClipMode := AClipMode;
end;
{@@ {@@
Finishes writing a Path, which was created in multiple Finishes writing a Path, which was created in multiple
steps using StartPath and AddPointToPath, steps using StartPath and AddPointToPath,
@ -885,15 +897,6 @@ procedure TvVectorialDocument.ClearTmpPath();
var var
segment, oldsegment: TPathSegment; segment, oldsegment: TPathSegment;
begin begin
// segment := FTmpPath.Points;
// Don't free segments, because they are used when the path is added
// while segment <> nil do
// begin
// oldsegment := segment;
// segment := segment^.Next;
// oldsegment^.Free;
// end;
FTmpPath.Points := nil; FTmpPath.Points := nil;
FTmpPath.PointsEnd := nil; FTmpPath.PointsEnd := nil;
FTmpPath.Len := 0; FTmpPath.Len := 0;
@ -1240,6 +1243,8 @@ begin
CurPoint := ASource.CurPoint; CurPoint := ASource.CurPoint;
Pen := ASource.Pen; Pen := ASource.Pen;
Brush := ASource.Brush; Brush := ASource.Brush;
ClipPath := ASource.ClipPath;
ClipMode := ASource.ClipMode;
end; end;
procedure TPath.PrepareForSequentialReading; procedure TPath.PrepareForSequentialReading;

View File

@ -4,16 +4,16 @@ unit fpvtocanvas;
interface interface
{.$define USE_LCL_CANVAS} {$define USE_LCL_CANVAS}
uses uses
Classes, SysUtils, Math, Classes, SysUtils, Math,
{$ifdef USE_LCL_CANVAS} {$ifdef USE_LCL_CANVAS}
Graphics, LCLIntf, Graphics, LCLIntf, LCLType,
{$endif} {$endif}
fpcanvas, fpcanvas,
fpimage, fpimage,
fpvectorial; fpvectorial, fpvutils;
procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
ADest: TFPCustomCanvas; ADest: TFPCustomCanvas;
@ -155,6 +155,11 @@ var
t: Double; t: Double;
// For polygons // For polygons
Points: array of TPoint; Points: array of TPoint;
// Clipping Region
{$ifdef USE_LCL_CANVAS}
ClipRegion, OldClipRegion: HRGN;
ACanvas: TCanvas absolute ADest;
{$endif}
begin begin
PosX := 0; PosX := 0;
PosY := 0; PosY := 0;
@ -162,17 +167,29 @@ begin
ADest.MoveTo(ADestX, ADestY); ADest.MoveTo(ADestX, ADestY);
CurPath.PrepareForSequentialReading;
// Set the path Pen and Brush options // Set the path Pen and Brush options
ADest.Pen.Style := CurPath.Pen.Style; ADest.Pen.Style := CurPath.Pen.Style;
ADest.Pen.Width := CurPath.Pen.Width; ADest.Pen.Width := CurPath.Pen.Width;
ADest.Pen.FPColor := CurPath.Pen.Color; ADest.Pen.FPColor := CurPath.Pen.Color;
ADest.Brush.FPColor := CurPath.Brush.Color; ADest.Brush.FPColor := CurPath.Brush.Color;
// Prepare the Clipping Region, if any
{$ifdef USE_LCL_CANVAS}
if CurPath.ClipPath <> nil then
begin
OldClipRegion := LCLIntf.CreateEmptyRegion();
GetClipRgn(ACanvas.Handle, OldClipRegion);
ClipRegion := ConvertPathToRegion(CurPath.ClipPath, ADestX, ADestY, AMulX, AMulY);
SelectClipRgn(ACanvas.Handle, ClipRegion);
DeleteObject(ClipRegion);
end;
{$endif}
// //
// For solid paths, draw a polygon instead // For solid paths, draw a polygon instead
// //
CurPath.PrepareForSequentialReading;
if CurPath.Brush.Style = bsSolid then if CurPath.Brush.Style = bsSolid then
begin begin
ADest.Brush.Style := CurPath.Brush.Style; ADest.Brush.Style := CurPath.Brush.Style;
@ -281,6 +298,14 @@ begin
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG} {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
WriteLn(''); WriteLn('');
{$endif} {$endif}
// Restores the previous Clip Region
{$ifdef USE_LCL_CANVAS}
if CurPath.ClipPath <> nil then
begin
SelectClipRgn(ACanvas.Handle, OldClipRegion); //Using OldClipRegion crashes in Qt
end;
{$endif}
end; end;
procedure DrawFPVEntityToCanvas(ASource: TvVectorialDocument; CurEntity: TvEntity; procedure DrawFPVEntityToCanvas(ASource: TvVectorialDocument; CurEntity: TvEntity;

View File

@ -11,6 +11,8 @@ AUTHORS: Felipe Monteiro de Carvalho
} }
unit fpvutils; unit fpvutils;
{$define USE_LCL_CANVAS}
{$ifdef fpc} {$ifdef fpc}
{$mode delphi} {$mode delphi}
{$endif} {$endif}
@ -19,6 +21,9 @@ interface
uses uses
Classes, SysUtils, Math, Classes, SysUtils, Math,
{$ifdef USE_LCL_CANVAS}
Graphics, LCLIntf, LCLType,
{$endif}
fpvectorial, fpimage; fpvectorial, fpimage;
type type
@ -27,13 +32,20 @@ type
// Color Conversion routines // Color Conversion routines
function FPColorToRGBHexString(AColor: TFPColor): string; function FPColorToRGBHexString(AColor: TFPColor): string;
function RGBToFPColor(AR, AG, AB: byte): TFPColor; inline; function RGBToFPColor(AR, AG, AB: byte): TFPColor; inline;
// Other routine // Coordinate Conversion routines
function CanvasCoordsToFPVectorial(AY: Integer; AHeight: Integer): Integer; inline; function CanvasCoordsToFPVectorial(AY: Integer; AHeight: Integer): Integer; inline;
function CanvasTextPosToFPVectorial(AY: Integer; ACanvasHeight, ATextHeight: Integer): Integer; function CanvasTextPosToFPVectorial(AY: Integer; ACanvasHeight, ATextHeight: Integer): Integer;
function CoordToCanvasX(ACoord: Double; ADestX: Integer; AMulX: Double): Integer; inline;
function CoordToCanvasY(ACoord: Double; ADestY: Integer; AMulY: Double): Integer; inline;
// Other routines
function SeparateString(AString: string; ASeparator: char): T10Strings; function SeparateString(AString: string; ASeparator: char): T10Strings;
// Mathematical routines // Mathematical routines
procedure EllipticalArcToBezier(Xc, Yc, Rx, Ry, startAngle, endAngle: Double; var P1, P2, P3, P4: T3DPoint); procedure EllipticalArcToBezier(Xc, Yc, Rx, Ry, startAngle, endAngle: Double; var P1, P2, P3, P4: T3DPoint);
procedure CircularArcToBezier(Xc, Yc, R, startAngle, endAngle: Double; var P1, P2, P3, P4: T3DPoint); procedure CircularArcToBezier(Xc, Yc, R, startAngle, endAngle: Double; var P1, P2, P3, P4: T3DPoint);
// LCL-related routines
{$ifdef USE_LCL_CANVAS}
function ConvertPathToRegion(APath: TPath; ADestX, ADestY: Integer; AMulX, AMulY: Double): HRGN;
{$endif}
implementation implementation
@ -78,6 +90,16 @@ begin
Result := CanvasCoordsToFPVectorial(AY, ACanvasHeight) - ATextHeight; Result := CanvasCoordsToFPVectorial(AY, ACanvasHeight) - ATextHeight;
end; end;
function CoordToCanvasX(ACoord: Double; ADestX: Integer; AMulX: Double): Integer;
begin
Result := Round(ADestX + AmulX * ACoord);
end;
function CoordToCanvasY(ACoord: Double; ADestY: Integer; AMulY: Double): Integer;
begin
Result := Round(ADestY + AmulY * ACoord);
end;
{@@ {@@
Reads a string and separates it in substring Reads a string and separates it in substring
using ASeparator to delimite them. using ASeparator to delimite them.
@ -164,5 +186,38 @@ begin
EllipticalArcToBezier(Xc, Yc, R, R, startAngle, endAngle, P1, P2, P3, P4); EllipticalArcToBezier(Xc, Yc, R, R, startAngle, endAngle, P1, P2, P3, P4);
end; end;
{$ifdef USE_LCL_CANVAS}
function ConvertPathToRegion(APath: TPath; ADestX, ADestY: Integer; AMulX, AMulY: Double): HRGN;
var
i: Integer;
WindingMode: Integer;
Points: array of TPoint;
CoordX, CoordY: Integer;
// Segments
CurSegment: TPathSegment;
Cur2DSegment: T2DSegment absolute CurSegment;
begin
APath.PrepareForSequentialReading;
SetLength(Points, APath.Len);
for i := 0 to APath.Len - 1 do
begin
CurSegment := TPathSegment(APath.Next());
CoordX := CoordToCanvasX(Cur2DSegment.X, ADestX, AMulX);
CoordY := CoordToCanvasY(Cur2DSegment.Y, ADestY, AMulY);
Points[i].X := CoordX;
Points[i].Y := CoordY;
end;
if APath.ClipMode = vcmEvenOddRule then WindingMode := LCLType.ALTERNATE
else WindingMode := LCLType.WINDING;
Result := LCLIntf.CreatePolygonRgn(@Points[0], APath.Len, WindingMode);
end;
{$endif}
end. end.