mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-11-10 07:29:41 +01:00
fpvectorial: Merges the implementation of pen, brush and updates the svg output to use the pen
git-svn-id: trunk@17382 -
This commit is contained in:
parent
576072dc17
commit
bca76120f6
@ -13,7 +13,6 @@
|
|||||||
<Title Value="fpvwritetest"/>
|
<Title Value="fpvwritetest"/>
|
||||||
<ResourceType Value="res"/>
|
<ResourceType Value="res"/>
|
||||||
<UseXPManifest Value="True"/>
|
<UseXPManifest Value="True"/>
|
||||||
<Icon Value="0"/>
|
|
||||||
</General>
|
</General>
|
||||||
<i18n>
|
<i18n>
|
||||||
<EnableI18N LFM="False"/>
|
<EnableI18N LFM="False"/>
|
||||||
@ -21,6 +20,9 @@
|
|||||||
<VersionInfo>
|
<VersionInfo>
|
||||||
<StringTable ProductVersion=""/>
|
<StringTable ProductVersion=""/>
|
||||||
</VersionInfo>
|
</VersionInfo>
|
||||||
|
<BuildModes Count="1">
|
||||||
|
<Item1 Name="default" Default="True"/>
|
||||||
|
</BuildModes>
|
||||||
<PublishOptions>
|
<PublishOptions>
|
||||||
<Version Value="2"/>
|
<Version Value="2"/>
|
||||||
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
|
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
|
||||||
@ -29,6 +31,7 @@
|
|||||||
<RunParams>
|
<RunParams>
|
||||||
<local>
|
<local>
|
||||||
<FormatVersion Value="1"/>
|
<FormatVersion Value="1"/>
|
||||||
|
<LaunchingApplication PathPlusParams="\usr\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
|
||||||
</local>
|
</local>
|
||||||
</RunParams>
|
</RunParams>
|
||||||
<Units Count="1">
|
<Units Count="1">
|
||||||
@ -40,13 +43,13 @@
|
|||||||
</Units>
|
</Units>
|
||||||
</ProjectOptions>
|
</ProjectOptions>
|
||||||
<CompilerOptions>
|
<CompilerOptions>
|
||||||
<Version Value="9"/>
|
<Version Value="10"/>
|
||||||
<PathDelim Value="\"/>
|
<PathDelim Value="\"/>
|
||||||
<Target>
|
<Target>
|
||||||
<Filename Value="fpvwritetest"/>
|
<Filename Value="fpvwritetest"/>
|
||||||
</Target>
|
</Target>
|
||||||
<SearchPaths>
|
<SearchPaths>
|
||||||
<IncludeFiles Value="$(ProjOutDir)\"/>
|
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||||
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
|
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
|
||||||
</SearchPaths>
|
</SearchPaths>
|
||||||
<Other>
|
<Other>
|
||||||
|
|||||||
@ -22,7 +22,7 @@ program fpvwritetest;
|
|||||||
{$mode objfpc}{$H+}
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
uses
|
uses
|
||||||
fpvectorial, svgvectorialwriter;
|
fpvectorial, svgvectorialwriter, fpvutils;
|
||||||
|
|
||||||
const
|
const
|
||||||
cFormat = vfSVG;
|
cFormat = vfSVG;
|
||||||
@ -134,6 +134,51 @@ begin
|
|||||||
Vec.AddText(20, 20, 0, '20, 20 Mówić, cześć, Włosku, Parabéns.');
|
Vec.AddText(20, 20, 0, '20, 20 Mówić, cześć, Włosku, Parabéns.');
|
||||||
Vec.AddText(30, 30, 0, '30, 30 森林,是一个高密');
|
Vec.AddText(30, 30, 0, '30, 30 森林,是一个高密');
|
||||||
Vec.WriteToFile('multi_test_1' + cExtension, cFormat);
|
Vec.WriteToFile('multi_test_1' + cExtension, cFormat);
|
||||||
|
|
||||||
|
// pen_test_1 Tests the properties of the Pen
|
||||||
|
Vec.Clear;
|
||||||
|
Vec.StartPath(0, 20);
|
||||||
|
Vec.AddLineToPath(30, 30);
|
||||||
|
Vec.SetPenWidth(10);
|
||||||
|
Vec.EndPath();
|
||||||
|
Vec.StartPath(0, 0);
|
||||||
|
Vec.AddLineToPath(100, 0);
|
||||||
|
Vec.AddLineToPath(100, 100);
|
||||||
|
Vec.AddLineToPath(0, 100);
|
||||||
|
Vec.AddLineToPath(0, 0);
|
||||||
|
Vec.SetPenWidth(10);
|
||||||
|
Vec.EndPath();
|
||||||
|
Vec.StartPath(0, 0);
|
||||||
|
Vec.AddLineToPath(10, 10);
|
||||||
|
Vec.AddBezierToPath(10, 20, 20, 20, 20, 10);
|
||||||
|
Vec.AddLineToPath(30, 0);
|
||||||
|
Vec.SetPenWidth(10);
|
||||||
|
Vec.EndPath();
|
||||||
|
Vec.WriteToFile('pen_test_1' + cExtension, cFormat);
|
||||||
|
|
||||||
|
// pen_test_2 Tests the properties of the Pen
|
||||||
|
Vec.Clear;
|
||||||
|
Vec.StartPath(0, 20);
|
||||||
|
Vec.AddLineToPath(30, 30);
|
||||||
|
Vec.SetPenWidth(10);
|
||||||
|
Vec.SetPenColor(RGBToVColor(255, 0, 0));
|
||||||
|
Vec.EndPath();
|
||||||
|
Vec.StartPath(0, 0);
|
||||||
|
Vec.AddLineToPath(100, 0);
|
||||||
|
Vec.AddLineToPath(100, 100);
|
||||||
|
Vec.AddLineToPath(0, 100);
|
||||||
|
Vec.AddLineToPath(0, 0);
|
||||||
|
Vec.SetPenWidth(10);
|
||||||
|
Vec.SetPenColor(RGBToVColor(0, 255, 0));
|
||||||
|
Vec.EndPath();
|
||||||
|
Vec.StartPath(0, 0);
|
||||||
|
Vec.AddLineToPath(10, 10);
|
||||||
|
Vec.AddBezierToPath(10, 20, 20, 20, 20, 10);
|
||||||
|
Vec.AddLineToPath(30, 0);
|
||||||
|
Vec.SetPenWidth(10);
|
||||||
|
Vec.SetPenColor(RGBToVColor(0, 0, 255));
|
||||||
|
Vec.EndPath();
|
||||||
|
Vec.WriteToFile('pen_test_2' + cExtension, cFormat);
|
||||||
finally
|
finally
|
||||||
Vec.Free;
|
Vec.Free;
|
||||||
end;
|
end;
|
||||||
|
|||||||
@ -45,6 +45,17 @@ type
|
|||||||
Red, Green, Blue, Alpha: Byte;
|
Red, Green, Blue, Alpha: Byte;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TvPen = record
|
||||||
|
Color: TvColor;
|
||||||
|
Style: TFPPenStyle;
|
||||||
|
Width: Integer;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TvBrush = record
|
||||||
|
Color: TvColor;
|
||||||
|
Style: TFPBrushStyle;
|
||||||
|
end;
|
||||||
|
|
||||||
const
|
const
|
||||||
FPValphaTransparent = $00;
|
FPValphaTransparent = $00;
|
||||||
FPValphaOpaque = $FF;
|
FPValphaOpaque = $FF;
|
||||||
@ -59,7 +70,7 @@ type
|
|||||||
P3DPoint = ^T3DPoint;
|
P3DPoint = ^T3DPoint;
|
||||||
|
|
||||||
TSegmentType = (
|
TSegmentType = (
|
||||||
st2DLine, st2DBezier,
|
st2DLine, st2DLineWithPen, st2DBezier,
|
||||||
st3DLine, st3DBezier, stMoveTo);
|
st3DLine, st3DBezier, stMoveTo);
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
@ -75,10 +86,6 @@ type
|
|||||||
// Fields for linking the list
|
// Fields for linking the list
|
||||||
Previous: TPathSegment;
|
Previous: TPathSegment;
|
||||||
Next: TPathSegment;
|
Next: TPathSegment;
|
||||||
// Data fields
|
|
||||||
PenColor: TvColor;
|
|
||||||
PenStyle: TFPPenStyle;
|
|
||||||
PenWidth: Integer;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
@ -93,6 +100,11 @@ type
|
|||||||
X, Y: Double;
|
X, Y: Double;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
T2DSegmentWithPen = class(T2DSegment)
|
||||||
|
public
|
||||||
|
Pen: TvPen;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
In Bezier segments, we remain using the X and Y coordinates for the ending point.
|
In Bezier segments, we remain using the X and Y coordinates for the ending point.
|
||||||
The starting point is where the previous segment ended, so that the intermediary
|
The starting point is where the previous segment ended, so that the intermediary
|
||||||
@ -124,6 +136,13 @@ type
|
|||||||
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
|
||||||
|
{@@ The global Pen for the entire path. This Pen might be overriden by
|
||||||
|
individual elements of the polyline. }
|
||||||
|
Pen: TvPen;
|
||||||
|
{@@ Sets a Brush to paint the inner area inside the path.
|
||||||
|
There is no inner area if Brush.Style = bsClear, which is the default. }
|
||||||
|
Brush: TvBrush;
|
||||||
|
constructor Create();
|
||||||
procedure Assign(APath: TPath);
|
procedure Assign(APath: TPath);
|
||||||
function Count(): TPathSegment;
|
function Count(): TPathSegment;
|
||||||
procedure PrepareForSequentialReading;
|
procedure PrepareForSequentialReading;
|
||||||
@ -139,23 +158,18 @@ type
|
|||||||
TvText = class
|
TvText = class
|
||||||
public
|
public
|
||||||
X, Y, Z: Double; // Z is ignored in 2D formats
|
X, Y, Z: Double; // Z is ignored in 2D formats
|
||||||
|
Value: utf8string;
|
||||||
|
FontColor: TvColor;
|
||||||
FontSize: integer;
|
FontSize: integer;
|
||||||
FontName: utf8string;
|
FontName: utf8string;
|
||||||
Value: utf8string;
|
|
||||||
Color: TvColor;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
}
|
}
|
||||||
TvEntity = class
|
TvEntity = class
|
||||||
public
|
public
|
||||||
// Pen
|
Pen: TvPen;
|
||||||
PenColor: TvColor;
|
Brush: TvBrush;
|
||||||
PenStyle: TFPPenStyle;
|
|
||||||
PenWidth: Integer;
|
|
||||||
// Brush
|
|
||||||
BrushStyle: TFPBrushStyle;
|
|
||||||
BrushColor: TvColor;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
@ -253,6 +267,11 @@ type
|
|||||||
procedure AddLineToPath(AX, AY, AZ: Double); overload;
|
procedure AddLineToPath(AX, AY, AZ: Double); overload;
|
||||||
procedure AddBezierToPath(AX1, AY1, AX2, AY2, AX3, AY3: Double); overload;
|
procedure AddBezierToPath(AX1, AY1, AX2, AY2, AX3, AY3: Double); overload;
|
||||||
procedure AddBezierToPath(AX1, AY1, AZ1, AX2, AY2, AZ2, AX3, AY3, AZ3: Double); overload;
|
procedure AddBezierToPath(AX1, AY1, AZ1, AX2, AY2, AZ2, AX3, AY3, AZ3: Double); overload;
|
||||||
|
procedure SetBrushColor(AColor: TvColor);
|
||||||
|
procedure SetBrushStyle(AStyle: TFPBrushStyle);
|
||||||
|
procedure SetPenColor(AColor: TvColor);
|
||||||
|
procedure SetPenStyle(AStyle: TFPPenStyle);
|
||||||
|
procedure SetPenWidth(AWidth: Integer);
|
||||||
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;
|
||||||
@ -550,20 +569,19 @@ begin
|
|||||||
segment.SegmentType := st2DLine;
|
segment.SegmentType := st2DLine;
|
||||||
segment.X := AX;
|
segment.X := AX;
|
||||||
segment.Y := AY;
|
segment.Y := AY;
|
||||||
segment.PenColor := clvBlack;
|
|
||||||
|
|
||||||
AppendSegmentToTmpPath(segment);
|
AppendSegmentToTmpPath(segment);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TvVectorialDocument.AddLineToPath(AX, AY: Double; AColor: TvColor);
|
procedure TvVectorialDocument.AddLineToPath(AX, AY: Double; AColor: TvColor);
|
||||||
var
|
var
|
||||||
segment: T2DSegment;
|
segment: T2DSegmentWithPen;
|
||||||
begin
|
begin
|
||||||
segment := T2DSegment.Create;
|
segment := T2DSegmentWithPen.Create;
|
||||||
segment.SegmentType := st2DLine;
|
segment.SegmentType := st2DLineWithPen;
|
||||||
segment.X := AX;
|
segment.X := AX;
|
||||||
segment.Y := AY;
|
segment.Y := AY;
|
||||||
segment.PenColor := AColor;
|
segment.Pen.Color := AColor;
|
||||||
|
|
||||||
AppendSegmentToTmpPath(segment);
|
AppendSegmentToTmpPath(segment);
|
||||||
end;
|
end;
|
||||||
@ -623,6 +641,31 @@ begin
|
|||||||
AppendSegmentToTmpPath(segment);
|
AppendSegmentToTmpPath(segment);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.SetBrushColor(AColor: TvColor);
|
||||||
|
begin
|
||||||
|
FTmPPath.Brush.Color := AColor;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.SetBrushStyle(AStyle: TFPBrushStyle);
|
||||||
|
begin
|
||||||
|
FTmPPath.Brush.Style := AStyle;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.SetPenColor(AColor: TvColor);
|
||||||
|
begin
|
||||||
|
FTmPPath.Pen.Color := AColor;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.SetPenStyle(AStyle: TFPPenStyle);
|
||||||
|
begin
|
||||||
|
FTmPPath.Pen.Style := AStyle;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.SetPenWidth(AWidth: Integer);
|
||||||
|
begin
|
||||||
|
FTmPPath.Pen.Width := AWidth;
|
||||||
|
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,
|
||||||
@ -683,7 +726,7 @@ begin
|
|||||||
lCircularArc.Radius := ARadius;
|
lCircularArc.Radius := ARadius;
|
||||||
lCircularArc.StartAngle := AStartAngle;
|
lCircularArc.StartAngle := AStartAngle;
|
||||||
lCircularArc.EndAngle := AEndAngle;
|
lCircularArc.EndAngle := AEndAngle;
|
||||||
lCircularArc.PenColor := AColor;
|
lCircularArc.Pen.Color := AColor;
|
||||||
FEntities.Add(lCircularArc);
|
FEntities.Add(lCircularArc);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -728,12 +771,13 @@ begin
|
|||||||
for i := 0 to Length(GvVectorialFormats) - 1 do
|
for i := 0 to Length(GvVectorialFormats) - 1 do
|
||||||
if GvVectorialFormats[i].Format = AFormat then
|
if GvVectorialFormats[i].Format = AFormat then
|
||||||
begin
|
begin
|
||||||
Result := GvVectorialFormats[i].WriterClass.Create;
|
if GvVectorialFormats[i].WriterClass <> nil then
|
||||||
|
Result := GvVectorialFormats[i].WriterClass.Create;
|
||||||
|
|
||||||
Break;
|
Break;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if Result = nil then raise Exception.Create('Unsuported vector graphics format.');
|
if Result = nil then raise Exception.Create('Unsupported vector graphics format.');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
@ -749,12 +793,13 @@ begin
|
|||||||
for i := 0 to Length(GvVectorialFormats) - 1 do
|
for i := 0 to Length(GvVectorialFormats) - 1 do
|
||||||
if GvVectorialFormats[i].Format = AFormat then
|
if GvVectorialFormats[i].Format = AFormat then
|
||||||
begin
|
begin
|
||||||
Result := GvVectorialFormats[i].ReaderClass.Create;
|
if GvVectorialFormats[i].ReaderClass <> nil then
|
||||||
|
Result := GvVectorialFormats[i].ReaderClass.Create;
|
||||||
|
|
||||||
Break;
|
Break;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if Result = nil then raise Exception.Create('Unsuported vector graphics format.');
|
if Result = nil then raise Exception.Create('Unsupported vector graphics format.');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TvVectorialDocument.ClearTmpPath();
|
procedure TvVectorialDocument.ClearTmpPath();
|
||||||
@ -1073,12 +1118,20 @@ end;
|
|||||||
|
|
||||||
{ TPath }
|
{ TPath }
|
||||||
|
|
||||||
|
constructor TPath.Create();
|
||||||
|
begin
|
||||||
|
Brush.Style := bsClear;
|
||||||
|
inherited Create();
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TPath.Assign(APath: TPath);
|
procedure TPath.Assign(APath: TPath);
|
||||||
begin
|
begin
|
||||||
Len := APath.Len;
|
Len := APath.Len;
|
||||||
Points := APath.Points;
|
Points := APath.Points;
|
||||||
PointsEnd := APath.PointsEnd;
|
PointsEnd := APath.PointsEnd;
|
||||||
CurPoint := APath.CurPoint;
|
CurPoint := APath.CurPoint;
|
||||||
|
Pen := APath.Pen;
|
||||||
|
Brush := APath.Brush;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPath.Count(): TPathSegment;
|
function TPath.Count(): TPathSegment;
|
||||||
|
|||||||
@ -4,7 +4,7 @@ unit fpvtocanvas;
|
|||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
{.$define USE_LCL_CANVAS}
|
{$define USE_LCL_CANVAS}
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, Math,
|
Classes, SysUtils, Math,
|
||||||
@ -115,7 +115,7 @@ end;
|
|||||||
|
|
||||||
DrawFPVectorialToCanvas(ASource, ADest, 0, ASource.Height, 1.0, -1.0);
|
DrawFPVectorialToCanvas(ASource, ADest, 0, ASource.Height, 1.0, -1.0);
|
||||||
}
|
}
|
||||||
{$define FPVECTORIAL_TOCANVAS_DEBUG}
|
{.$define FPVECTORIAL_TOCANVAS_DEBUG}
|
||||||
procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
|
procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
|
||||||
{$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
|
{$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
|
||||||
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||||
@ -187,15 +187,22 @@ begin
|
|||||||
Write(Format(' M%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
|
Write(Format(' M%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
|
||||||
{$endif}
|
{$endif}
|
||||||
end;
|
end;
|
||||||
st2DLine, st3DLine:
|
st2DLineWithPen:
|
||||||
begin
|
begin
|
||||||
{$ifdef USE_LCL_CANVAS}ADest.Pen.Color := VColorToTColor(Cur2DSegment.PenColor);{$endif}
|
{$ifdef USE_LCL_CANVAS}ADest.Pen.Color := VColorToTColor(T2DSegmentWithPen(Cur2DSegment).Pen.Color);{$endif}
|
||||||
ADest.LineTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
|
ADest.LineTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
|
||||||
{$ifdef USE_LCL_CANVAS}ADest.Pen.Color := clBlack;{$endif}
|
{$ifdef USE_LCL_CANVAS}ADest.Pen.Color := clBlack;{$endif}
|
||||||
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
|
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
|
||||||
Write(Format(' L%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
|
Write(Format(' L%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
|
||||||
{$endif}
|
{$endif}
|
||||||
end;
|
end;
|
||||||
|
st2DLine, st3DLine:
|
||||||
|
begin
|
||||||
|
ADest.LineTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
|
||||||
|
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
|
||||||
|
Write(Format(' L%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
|
||||||
|
{$endif}
|
||||||
|
end;
|
||||||
{ To draw a bezier we need to divide the interval in parts and make
|
{ To draw a bezier we need to divide the interval in parts and make
|
||||||
lines between this parts }
|
lines between this parts }
|
||||||
st2DBezier, st3DBezier:
|
st2DBezier, st3DBezier:
|
||||||
@ -321,7 +328,7 @@ begin
|
|||||||
WriteLn(Format('Drawing Arc Center=%f,%f Radius=%f StartAngle=%f AngleLength=%f',
|
WriteLn(Format('Drawing Arc Center=%f,%f Radius=%f StartAngle=%f AngleLength=%f',
|
||||||
[CurArc.CenterX, CurArc.CenterY, CurArc.Radius, IntStartAngle/16, IntAngleLength/16]));
|
[CurArc.CenterX, CurArc.CenterY, CurArc.Radius, IntStartAngle/16, IntAngleLength/16]));
|
||||||
{$endif}
|
{$endif}
|
||||||
ADest.Pen.Color := {$ifdef USE_LCL_CANVAS}VColorToTColor(CurArc.PenColor);{$else}VColorToFPColor(CurArc.PenColor);{$endif}
|
ADest.Pen.Color := {$ifdef USE_LCL_CANVAS}VColorToTColor(CurArc.Pen.Color);{$else}VColorToFPColor(CurArc.Pen.Color);{$endif}
|
||||||
ADest.Arc(
|
ADest.Arc(
|
||||||
BoundsLeft, BoundsTop, BoundsRight, BoundsBottom,
|
BoundsLeft, BoundsTop, BoundsRight, BoundsBottom,
|
||||||
IntStartAngle, IntAngleLength
|
IntStartAngle, IntAngleLength
|
||||||
|
|||||||
@ -13,7 +13,7 @@ unit svgvectorialwriter;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, math, fpvectorial;
|
Classes, SysUtils, math, fpvectorial, fpvutils;
|
||||||
|
|
||||||
type
|
type
|
||||||
{ TvSVGVectorialWriter }
|
{ TvSVGVectorialWriter }
|
||||||
@ -24,6 +24,7 @@ type
|
|||||||
procedure WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
|
procedure WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
procedure WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument);
|
procedure WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
procedure WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
|
procedure WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
|
procedure WritePath(AIndex: Integer; APath: TPath; AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
procedure WriteTexts(AStrings: TStrings; AData: TvVectorialDocument);
|
procedure WriteTexts(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
procedure ConvertFPVCoordinatesToSVGCoordinates(
|
procedure ConvertFPVCoordinatesToSVGCoordinates(
|
||||||
const AData: TvVectorialDocument;
|
const AData: TvVectorialDocument;
|
||||||
@ -60,6 +61,19 @@ begin
|
|||||||
AStrings.Add(' sodipodi:docname="New document 1">');
|
AStrings.Add(' sodipodi:docname="New document 1">');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TvSVGVectorialWriter.WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
lPath: TPath;
|
||||||
|
begin
|
||||||
|
for i := 0 to AData.GetPathCount() - 1 do
|
||||||
|
begin
|
||||||
|
lPath := AData.GetPath(i);
|
||||||
|
lPath.PrepareForSequentialReading;
|
||||||
|
WritePath(i ,lPath, AStrings, AData);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
SVG Coordinate system measures things only in pixels, so that we have to
|
SVG Coordinate system measures things only in pixels, so that we have to
|
||||||
hardcode a DPI value for the screen, which is usually 72.
|
hardcode a DPI value for the screen, which is usually 72.
|
||||||
@ -74,90 +88,98 @@ end;
|
|||||||
SVG uses commas "," to separate the X,Y coordinates, so it always uses points
|
SVG uses commas "," to separate the X,Y coordinates, so it always uses points
|
||||||
"." as decimal separators and uses no thousand separators
|
"." as decimal separators and uses no thousand separators
|
||||||
}
|
}
|
||||||
procedure TvSVGVectorialWriter.WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
|
procedure TvSVGVectorialWriter.WritePath(AIndex: Integer; APath: TPath; AStrings: TStrings;
|
||||||
|
AData: TvVectorialDocument);
|
||||||
var
|
var
|
||||||
i, j: Integer;
|
j: Integer;
|
||||||
PathStr: string;
|
PathStr: string;
|
||||||
lPath: TPath;
|
|
||||||
PtX, PtY, OldPtX, OldPtY: double;
|
PtX, PtY, OldPtX, OldPtY: double;
|
||||||
BezierCP1X, BezierCP1Y, BezierCP2X, BezierCP2Y: double;
|
BezierCP1X, BezierCP1Y, BezierCP2X, BezierCP2Y: double;
|
||||||
segment: TPathSegment;
|
segment: TPathSegment;
|
||||||
l2DSegment: T2DSegment absolute segment;
|
l2DSegment: T2DSegment absolute segment;
|
||||||
l2DBSegment: T2DBezierSegment absolute segment;
|
l2DBSegment: T2DBezierSegment absolute segment;
|
||||||
|
// Pen properties
|
||||||
|
lPenWidth: Integer;
|
||||||
|
lPenColor: string;
|
||||||
begin
|
begin
|
||||||
for i := 0 to AData.GetPathCount() - 1 do
|
OldPtX := 0;
|
||||||
|
OldPtY := 0;
|
||||||
|
PathStr := '';
|
||||||
|
|
||||||
|
APath.PrepareForSequentialReading();
|
||||||
|
|
||||||
|
for j := 0 to APath.Len - 1 do
|
||||||
begin
|
begin
|
||||||
OldPtX := 0;
|
segment := TPathSegment(APath.Next());
|
||||||
OldPtY := 0;
|
|
||||||
|
|
||||||
PathStr := '';
|
if (segment.SegmentType <> st2DLine)
|
||||||
lPath := AData.GetPath(i);
|
and (segment.SegmentType <> stMoveTo)
|
||||||
lPath.PrepareForSequentialReading;
|
and (segment.SegmentType <> st2DBezier)
|
||||||
|
then Break; // unsupported line type
|
||||||
|
|
||||||
for j := 0 to lPath.Len - 1 do
|
// Coordinate conversion from fpvectorial to SVG
|
||||||
|
ConvertFPVCoordinatesToSVGCoordinates(
|
||||||
|
AData, l2DSegment.X, l2DSegment.Y, PtX, PtY);
|
||||||
|
PtX := PtX - OldPtX;
|
||||||
|
PtY := PtY - OldPtY;
|
||||||
|
|
||||||
|
if (segment.SegmentType = stMoveTo) then
|
||||||
begin
|
begin
|
||||||
segment := TPathSegment(lPath.Next());
|
PathStr := PathStr + 'm '
|
||||||
|
+ FloatToStr(PtX, FPointSeparator) + ','
|
||||||
if (segment.SegmentType <> st2DLine)
|
+ FloatToStr(PtY, FPointSeparator) + ' ';
|
||||||
and (segment.SegmentType <> stMoveTo)
|
end
|
||||||
and (segment.SegmentType <> st2DBezier)
|
else if (segment.SegmentType = st2DLine) then
|
||||||
then Break; // unsupported line type
|
begin
|
||||||
|
PathStr := PathStr + 'l '
|
||||||
// Coordinate conversion from fpvectorial to SVG
|
+ FloatToStr(PtX, FPointSeparator) + ','
|
||||||
|
+ FloatToStr(PtY, FPointSeparator) + ' ';
|
||||||
|
end
|
||||||
|
else if (segment.SegmentType = st2DBezier) then
|
||||||
|
begin
|
||||||
|
// Converts all coordinates to absolute values
|
||||||
ConvertFPVCoordinatesToSVGCoordinates(
|
ConvertFPVCoordinatesToSVGCoordinates(
|
||||||
AData, l2DSegment.X, l2DSegment.Y, PtX, PtY);
|
AData, l2DBSegment.X2, l2DBSegment.Y2, BezierCP1X, BezierCP1Y);
|
||||||
PtX := PtX - OldPtX;
|
ConvertFPVCoordinatesToSVGCoordinates(
|
||||||
PtY := PtY - OldPtY;
|
AData, l2DBSegment.X3, l2DBSegment.Y3, BezierCP2X, BezierCP2Y);
|
||||||
|
|
||||||
if (segment.SegmentType = stMoveTo) then
|
// Transforms them into values relative to the initial point
|
||||||
begin
|
BezierCP1X := BezierCP1X - OldPtX;
|
||||||
PathStr := PathStr + 'm '
|
BezierCP1Y := BezierCP1Y - OldPtY;
|
||||||
+ FloatToStr(PtX, FPointSeparator) + ','
|
BezierCP2X := BezierCP2X - OldPtX;
|
||||||
+ FloatToStr(PtY, FPointSeparator) + ' ';
|
BezierCP2Y := BezierCP2Y - OldPtY;
|
||||||
end
|
|
||||||
else if (segment.SegmentType = st2DLine) then
|
|
||||||
begin
|
|
||||||
PathStr := PathStr + 'l '
|
|
||||||
+ FloatToStr(PtX, FPointSeparator) + ','
|
|
||||||
+ FloatToStr(PtY, FPointSeparator) + ' ';
|
|
||||||
end
|
|
||||||
else if (segment.SegmentType = st2DBezier) then
|
|
||||||
begin
|
|
||||||
// Converts all coordinates to absolute values
|
|
||||||
ConvertFPVCoordinatesToSVGCoordinates(
|
|
||||||
AData, l2DBSegment.X2, l2DBSegment.Y2, BezierCP1X, BezierCP1Y);
|
|
||||||
ConvertFPVCoordinatesToSVGCoordinates(
|
|
||||||
AData, l2DBSegment.X3, l2DBSegment.Y3, BezierCP2X, BezierCP2Y);
|
|
||||||
|
|
||||||
// Transforms them into values relative to the initial point
|
// PtX and PtY already contains the destination point
|
||||||
BezierCP1X := BezierCP1X - OldPtX;
|
|
||||||
BezierCP1Y := BezierCP1Y - OldPtY;
|
|
||||||
BezierCP2X := BezierCP2X - OldPtX;
|
|
||||||
BezierCP2Y := BezierCP2Y - OldPtY;
|
|
||||||
|
|
||||||
// PtX and PtY already contains the destination point
|
// Now render our 2D cubic bezier
|
||||||
|
PathStr := PathStr + 'c '
|
||||||
// Now render our 2D cubic bezier
|
+ FloatToStr(BezierCP1X, FPointSeparator) + ','
|
||||||
PathStr := PathStr + 'c '
|
+ FloatToStr(BezierCP1Y, FPointSeparator) + ' '
|
||||||
+ FloatToStr(BezierCP1X, FPointSeparator) + ','
|
+ FloatToStr(BezierCP2X, FPointSeparator) + ','
|
||||||
+ FloatToStr(BezierCP1Y, FPointSeparator) + ' '
|
+ FloatToStr(BezierCP2Y, FPointSeparator) + ' '
|
||||||
+ FloatToStr(BezierCP2X, FPointSeparator) + ','
|
+ FloatToStr(PtX, FPointSeparator) + ','
|
||||||
+ FloatToStr(BezierCP2Y, FPointSeparator) + ' '
|
+ FloatToStr(PtY, FPointSeparator) + ' '
|
||||||
+ FloatToStr(PtX, FPointSeparator) + ','
|
;
|
||||||
+ FloatToStr(PtY, FPointSeparator) + ' '
|
|
||||||
;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Store the current position for future points
|
|
||||||
OldPtX := OldPtX + PtX;
|
|
||||||
OldPtY := OldPtY + PtY;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
AStrings.Add(' <path');
|
// Store the current position for future points
|
||||||
AStrings.Add(' style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"');
|
OldPtX := OldPtX + PtX;
|
||||||
AStrings.Add(' d="' + PathStr + '"');
|
OldPtY := OldPtY + PtY;
|
||||||
AStrings.Add(' id="path' + IntToStr(i) + '" />');
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Get the Pen Width
|
||||||
|
if APath.Pen.Width >= 1 then lPenWidth := APath.Pen.Width
|
||||||
|
else lPenWidth := 1;
|
||||||
|
|
||||||
|
// Get the Pen Color
|
||||||
|
lPenColor := VColorToRGBHexString(APath.Pen.Color);
|
||||||
|
|
||||||
|
AStrings.Add(' <path');
|
||||||
|
AStrings.Add(Format(' style="fill:none;stroke:#%s;stroke-width:%dpx;'
|
||||||
|
+ 'stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"',
|
||||||
|
[lPenColor, lPenWidth]));
|
||||||
|
AStrings.Add(' d="' + PathStr + '"');
|
||||||
|
AStrings.Add(' id="path' + IntToStr(AIndex) + '" />');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TvSVGVectorialWriter.ConvertFPVCoordinatesToSVGCoordinates(
|
procedure TvSVGVectorialWriter.ConvertFPVCoordinatesToSVGCoordinates(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user