You've already forked lazarus-ccr
fpvectorial: Major rework to have a single list of entities, allowing to use that as a Z-Order
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1686 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -148,22 +148,22 @@ const
|
||||
// Valid for DXF up to AutoCad 2004, after that RGB is available
|
||||
AUTOCAD_COLOR_PALETTE: array[0..15] of TFPColor =
|
||||
(
|
||||
(Red: $0000; Green: $0000; Blue: $0000; Alpha: FPValphaOpaque), // 0 - Black
|
||||
(Red: $0000; Green: $0000; Blue: $8080; Alpha: FPValphaOpaque), // 1 - Dark blue
|
||||
(Red: $0000; Green: $8080; Blue: $0000; Alpha: FPValphaOpaque), // 2 - Dark green
|
||||
(Red: $0000; Green: $8080; Blue: $8080; Alpha: FPValphaOpaque), // 3 - Dark cyan
|
||||
(Red: $8080; Green: $0000; Blue: $0000; Alpha: FPValphaOpaque), // 4 - Dark red
|
||||
(Red: $8080; Green: $0000; Blue: $8080; Alpha: FPValphaOpaque), // 5 - Dark Magenta
|
||||
(Red: $8080; Green: $8080; Blue: $0000; Alpha: FPValphaOpaque), // 6 - Dark
|
||||
(Red: $c0c0; Green: $c0c0; Blue: $c0c0; Alpha: FPValphaOpaque), // 7 - Light Gray
|
||||
(Red: $8080; Green: $8080; Blue: $8080; Alpha: FPValphaOpaque), // 8 - Medium Gray
|
||||
(Red: $0000; Green: $0000; Blue: $ffff; Alpha: FPValphaOpaque), // 9 - Light blue
|
||||
(Red: $0000; Green: $ffff; Blue: $0000; Alpha: FPValphaOpaque), // 10 - Light green
|
||||
(Red: $0000; Green: $ffff; Blue: $ffff; Alpha: FPValphaOpaque), // 11 - Light cyan
|
||||
(Red: $ffff; Green: $0000; Blue: $0000; Alpha: FPValphaOpaque), // 12 - Light red
|
||||
(Red: $ffff; Green: $0000; Blue: $ffff; Alpha: FPValphaOpaque), // 13 - Light Magenta
|
||||
(Red: $ffff; Green: $ffff; Blue: $0000; Alpha: FPValphaOpaque), // 14 - Light Yellow
|
||||
(Red: $ffff; Green: $ffff; Blue: $ffff; Alpha: FPValphaOpaque) // 15 - White
|
||||
(Red: $0000; Green: $0000; Blue: $0000; Alpha: alphaOpaque), // 0 - Black
|
||||
(Red: $0000; Green: $0000; Blue: $8080; Alpha: alphaOpaque), // 1 - Dark blue
|
||||
(Red: $0000; Green: $8080; Blue: $0000; Alpha: alphaOpaque), // 2 - Dark green
|
||||
(Red: $0000; Green: $8080; Blue: $8080; Alpha: alphaOpaque), // 3 - Dark cyan
|
||||
(Red: $8080; Green: $0000; Blue: $0000; Alpha: alphaOpaque), // 4 - Dark red
|
||||
(Red: $8080; Green: $0000; Blue: $8080; Alpha: alphaOpaque), // 5 - Dark Magenta
|
||||
(Red: $8080; Green: $8080; Blue: $0000; Alpha: alphaOpaque), // 6 - Dark
|
||||
(Red: $c0c0; Green: $c0c0; Blue: $c0c0; Alpha: alphaOpaque), // 7 - Light Gray
|
||||
(Red: $8080; Green: $8080; Blue: $8080; Alpha: alphaOpaque), // 8 - Medium Gray
|
||||
(Red: $0000; Green: $0000; Blue: $ffff; Alpha: alphaOpaque), // 9 - Light blue
|
||||
(Red: $0000; Green: $ffff; Blue: $0000; Alpha: alphaOpaque), // 10 - Light green
|
||||
(Red: $0000; Green: $ffff; Blue: $ffff; Alpha: alphaOpaque), // 11 - Light cyan
|
||||
(Red: $ffff; Green: $0000; Blue: $0000; Alpha: alphaOpaque), // 12 - Light red
|
||||
(Red: $ffff; Green: $0000; Blue: $ffff; Alpha: alphaOpaque), // 13 - Light Magenta
|
||||
(Red: $ffff; Green: $ffff; Blue: $0000; Alpha: alphaOpaque), // 14 - Light Yellow
|
||||
(Red: $ffff; Green: $ffff; Blue: $ffff; Alpha: alphaOpaque) // 15 - White
|
||||
);
|
||||
|
||||
{ TDXFToken }
|
||||
|
@ -44,6 +44,8 @@ const
|
||||
STR_ENCAPSULATEDPOSTSCRIPT_EXTENSION = '.eps';
|
||||
|
||||
type
|
||||
{ Pen, Brush and Font }
|
||||
|
||||
TvPen = record
|
||||
Color: TFPColor;
|
||||
Style: TFPPenStyle;
|
||||
@ -55,11 +57,20 @@ type
|
||||
Style: TFPBrushStyle;
|
||||
end;
|
||||
|
||||
const
|
||||
FPValphaTransparent = $00;
|
||||
FPValphaOpaque = $FF;
|
||||
TvFont = record
|
||||
Color: TFPColor;
|
||||
Size: integer;
|
||||
Name: utf8string;
|
||||
{@@
|
||||
Font orientation is measured in degrees and uses the
|
||||
same direction as the LCL TFont.orientation, which is counter-clockwise.
|
||||
Zero is the normal, horizontal, orientation.
|
||||
}
|
||||
Orientation: Double;
|
||||
end;
|
||||
|
||||
{ Coordinates and polyline segments }
|
||||
|
||||
type
|
||||
T3DPoint = record
|
||||
X, Y, Z: Double;
|
||||
end;
|
||||
@ -128,60 +139,47 @@ type
|
||||
X3, Y3, Z3: Double;
|
||||
end;
|
||||
|
||||
TPath = class
|
||||
{ Now all elements }
|
||||
|
||||
{@@
|
||||
All elements should derive from TvEntity, regardless of whatever properties
|
||||
they might contain.
|
||||
}
|
||||
|
||||
TvEntity = class
|
||||
public
|
||||
{@@ The global Pen for the entire entity. In the case of paths, individual
|
||||
elements might be able to override this setting. }
|
||||
Pen: TvPen;
|
||||
{@@ The global Brush for the entire entity. In the case of paths, individual
|
||||
elements might be able to override this setting. }
|
||||
Brush: TvBrush;
|
||||
constructor Create; virtual;
|
||||
end;
|
||||
|
||||
TPath = class(TvEntity)
|
||||
Len: Integer;
|
||||
Points: TPathSegment; // Beginning of the double-linked list
|
||||
PointsEnd: TPathSegment; // End of the double-linked list
|
||||
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(ASource: TPath);
|
||||
procedure PrepareForSequentialReading;
|
||||
function Next(): TPathSegment;
|
||||
end;
|
||||
|
||||
TvFont = record
|
||||
Color: TFPColor;
|
||||
Size: integer;
|
||||
Name: utf8string;
|
||||
{@@
|
||||
Font orientation is measured in degrees and uses the
|
||||
same direction as the LCL TFont.orientation, which is counter-clockwise.
|
||||
Zero is the normal, horizontal, orientation.
|
||||
}
|
||||
Orientation: Double;
|
||||
end;
|
||||
|
||||
{@@
|
||||
TvText represents a text in memory.
|
||||
|
||||
At the moment fonts are unsupported, only simple texts
|
||||
up to 255 chars are supported.
|
||||
}
|
||||
TvText = class
|
||||
TvText = class(TvEntity)
|
||||
public
|
||||
X, Y, Z: Double; // Z is ignored in 2D formats
|
||||
Value: utf8string;
|
||||
Font: TvFont;
|
||||
end;
|
||||
|
||||
{@@
|
||||
}
|
||||
|
||||
{ TvEntity }
|
||||
|
||||
TvEntity = class
|
||||
public
|
||||
Pen: TvPen;
|
||||
Brush: TvBrush;
|
||||
constructor Create; virtual;
|
||||
end;
|
||||
|
||||
{@@
|
||||
}
|
||||
TvCircle = class(TvEntity)
|
||||
@ -200,9 +198,6 @@ type
|
||||
|
||||
{@@
|
||||
}
|
||||
|
||||
{ TvEllipse }
|
||||
|
||||
TvEllipse = class(TvEntity)
|
||||
public
|
||||
// Mandatory fields
|
||||
@ -215,6 +210,8 @@ type
|
||||
end;
|
||||
|
||||
{@@
|
||||
The brush has no effect in this class
|
||||
|
||||
DimensionLeft ---text--- DimensionRight
|
||||
| |
|
||||
| | BaseRight
|
||||
@ -239,8 +236,6 @@ type
|
||||
|
||||
TvVectorialDocument = class
|
||||
private
|
||||
FPaths: TFPList;
|
||||
FTexts: TFPList;
|
||||
FEntities: TFPList;
|
||||
FTmpPath: TPath;
|
||||
FTmpText: TvText;
|
||||
@ -255,6 +250,8 @@ type
|
||||
{ Base methods }
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure Assign(ASource: TvVectorialDocument);
|
||||
procedure AssignTo(ADest: TvVectorialDocument);
|
||||
procedure WriteToFile(AFileName: string; AFormat: TvVectorialFormat); overload;
|
||||
procedure WriteToFile(AFileName: string); overload;
|
||||
procedure WriteToStream(AStream: TStream; AFormat: TvVectorialFormat);
|
||||
@ -268,16 +265,13 @@ type
|
||||
{ Data reading methods }
|
||||
function GetPath(ANum: Cardinal): TPath;
|
||||
function GetPathCount: Integer;
|
||||
function GetText(ANum: Cardinal): TvText;
|
||||
function GetTextCount: Integer;
|
||||
function GetEntity(ANum: Cardinal): TvEntity;
|
||||
function GetEntityCount: Integer;
|
||||
function GetEntitiesCount: Integer;
|
||||
{ Data removing methods }
|
||||
procedure Clear;
|
||||
procedure RemoveAllPaths;
|
||||
procedure RemoveAllTexts;
|
||||
{ Data writing methods }
|
||||
procedure AddPath(APath: TPath);
|
||||
procedure AddEntity(AEntity: TvEntity);
|
||||
procedure AddPathCopyMem(APath: TPath);
|
||||
procedure StartPath(AX, AY: Double); overload;
|
||||
procedure StartPath(); overload;
|
||||
procedure AddMoveToPath(AX, AY: Double);
|
||||
@ -517,8 +511,6 @@ constructor TvVectorialDocument.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
FPaths := TFPList.Create;
|
||||
FTexts := TFPList.Create;
|
||||
FEntities := TFPList.Create;
|
||||
FTmpPath := TPath.Create;
|
||||
end;
|
||||
@ -530,40 +522,35 @@ destructor TvVectorialDocument.Destroy;
|
||||
begin
|
||||
Clear;
|
||||
|
||||
FPaths.Free;
|
||||
FTexts.Free;
|
||||
FEntities.Free;
|
||||
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{@@
|
||||
Clears the list of Vectors and releases their memory.
|
||||
}
|
||||
procedure TvVectorialDocument.RemoveAllPaths;
|
||||
procedure TvVectorialDocument.Assign(ASource: TvVectorialDocument);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
// FPaths.ForEachCall(RemoveCallback, nil);
|
||||
FPaths.Clear;
|
||||
Clear;
|
||||
|
||||
for i := 0 to ASource.GetEntitiesCount - 1 do
|
||||
Self.AddEntity(ASource.GetEntity(i));
|
||||
end;
|
||||
|
||||
procedure TvVectorialDocument.RemoveAllTexts;
|
||||
procedure TvVectorialDocument.AssignTo(ADest: TvVectorialDocument);
|
||||
begin
|
||||
// FTexts.ForEachCall(RemoveCallback, nil);
|
||||
FTexts.Clear;
|
||||
ADest.Assign(Self);
|
||||
end;
|
||||
|
||||
procedure TvVectorialDocument.AddPath(APath: TPath);
|
||||
procedure TvVectorialDocument.AddPathCopyMem(APath: TPath);
|
||||
var
|
||||
lPath: TPath;
|
||||
Len: Integer;
|
||||
begin
|
||||
lPath := TPath.Create;
|
||||
lPath.Assign(APath);
|
||||
FPaths.Add(Pointer(lPath));
|
||||
AddEntity(lPath);
|
||||
//WriteLn(':>TvVectorialDocument.AddPath 1 Len = ', Len);
|
||||
//WriteLn(':>TvVectorialDocument.AddPath 2');
|
||||
//WriteLn(':>TvVectorialDocument.AddPath 3');
|
||||
//WriteLn(':>TvVectorialDocument.AddPath 4');
|
||||
end;
|
||||
|
||||
{@@
|
||||
@ -746,7 +733,7 @@ end;
|
||||
procedure TvVectorialDocument.EndPath();
|
||||
begin
|
||||
if FTmPPath.Len = 0 then Exit;
|
||||
AddPath(FTmPPath);
|
||||
AddPathCopyMem(FTmPPath);
|
||||
ClearTmpPath();
|
||||
end;
|
||||
|
||||
@ -761,7 +748,7 @@ begin
|
||||
lText.Z := AZ;
|
||||
lText.Font.Name := FontName;
|
||||
lText.Font.Size := FontSize;
|
||||
FTexts.Add(lText);
|
||||
AddEntity(lText);
|
||||
end;
|
||||
|
||||
procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; AStr: utf8string);
|
||||
@ -778,7 +765,7 @@ begin
|
||||
lCircle.CenterY := ACenterY;
|
||||
lCircle.CenterZ := ACenterZ;
|
||||
lCircle.Radius := ARadius;
|
||||
FEntities.Add(lCircle);
|
||||
AddEntity(lCircle);
|
||||
end;
|
||||
|
||||
procedure TvVectorialDocument.AddCircularArc(ACenterX, ACenterY, ACenterZ,
|
||||
@ -794,7 +781,7 @@ begin
|
||||
lCircularArc.StartAngle := AStartAngle;
|
||||
lCircularArc.EndAngle := AEndAngle;
|
||||
lCircularArc.Pen.Color := AColor;
|
||||
FEntities.Add(lCircularArc);
|
||||
AddEntity(lCircularArc);
|
||||
end;
|
||||
|
||||
procedure TvVectorialDocument.AddEllipse(CenterX, CenterY, CenterZ,
|
||||
@ -809,7 +796,15 @@ begin
|
||||
lEllipse.MajorHalfAxis := MajorHalfAxis;
|
||||
lEllipse.MinorHalfAxis := MinorHalfAxis;
|
||||
lEllipse.Angle := Angle;
|
||||
FEntities.Add(lEllipse);
|
||||
AddEntity(lEllipse);
|
||||
end;
|
||||
|
||||
{@@
|
||||
Don't free the passed TvText because it will be added directly to the list
|
||||
}
|
||||
procedure TvVectorialDocument.AddEntity(AEntity: TvEntity);
|
||||
begin
|
||||
FEntities.Add(Pointer(AEntity));
|
||||
end;
|
||||
|
||||
procedure TvVectorialDocument.AddAlignedDimension(BaseLeft, BaseRight,
|
||||
@ -822,7 +817,7 @@ begin
|
||||
lDim.BaseRight := BaseRight;
|
||||
lDim.DimensionLeft := DimLeft;
|
||||
lDim.DimensionRight := DimRight;
|
||||
FEntities.Add(lDim);
|
||||
AddEntity(lDim);
|
||||
end;
|
||||
|
||||
{@@
|
||||
@ -1062,31 +1057,32 @@ begin
|
||||
end;
|
||||
|
||||
function TvVectorialDocument.GetPath(ANum: Cardinal): TPath;
|
||||
var
|
||||
i: Integer;
|
||||
Index: Integer = - 1;
|
||||
begin
|
||||
if ANum >= FPaths.Count then raise Exception.Create('TvVectorialDocument.GetPath: Path number out of bounds');
|
||||
Result := nil;
|
||||
|
||||
if FPaths.Items[ANum] = nil then raise Exception.Create('TvVectorialDocument.GetPath: Invalid Path number');
|
||||
if ANum >= FEntities.Count then raise Exception.Create('TvVectorialDocument.GetPath: Path number out of bounds');
|
||||
|
||||
Result := TPath(FPaths.Items[ANum]);
|
||||
for i := 0 to FEntities.Count - 1 do
|
||||
begin
|
||||
if TvEntity(FEntities.Items[i]) is TPath then
|
||||
begin
|
||||
Inc(Index);
|
||||
if Index = ANum then Result := TPath(FEntities.Items[i]);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TvVectorialDocument.GetPathCount: Integer;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
Result := FPaths.Count;
|
||||
end;
|
||||
Result := 0;
|
||||
|
||||
function TvVectorialDocument.GetText(ANum: Cardinal): TvText;
|
||||
begin
|
||||
if ANum >= FTexts.Count then raise Exception.Create('TvVectorialDocument.GetText: Text number out of bounds');
|
||||
|
||||
if FTexts.Items[ANum] = nil then raise Exception.Create('TvVectorialDocument.GetText: Invalid Text number');
|
||||
|
||||
Result := TvText(FTexts.Items[ANum]);
|
||||
end;
|
||||
|
||||
function TvVectorialDocument.GetTextCount: Integer;
|
||||
begin
|
||||
Result := FTexts.Count;
|
||||
for i := 0 to FEntities.Count - 1 do
|
||||
if TvEntity(FEntities.Items[i]) is TPath then Inc(Result);
|
||||
end;
|
||||
|
||||
function TvVectorialDocument.GetEntity(ANum: Cardinal): TvEntity;
|
||||
@ -1098,7 +1094,7 @@ begin
|
||||
Result := TvEntity(FEntities.Items[ANum]);
|
||||
end;
|
||||
|
||||
function TvVectorialDocument.GetEntityCount: Integer;
|
||||
function TvVectorialDocument.GetEntitiesCount: Integer;
|
||||
begin
|
||||
Result := FEntities.Count;
|
||||
end;
|
||||
@ -1108,8 +1104,7 @@ end;
|
||||
}
|
||||
procedure TvVectorialDocument.Clear;
|
||||
begin
|
||||
RemoveAllPaths();
|
||||
RemoveAllTexts();
|
||||
FEntities.Clear();
|
||||
end;
|
||||
|
||||
{ TvCustomVectorialReader }
|
||||
@ -1220,20 +1215,14 @@ end;
|
||||
|
||||
{ TPath }
|
||||
|
||||
constructor TPath.Create();
|
||||
procedure TPath.Assign(ASource: TPath);
|
||||
begin
|
||||
Brush.Style := bsClear;
|
||||
inherited Create();
|
||||
end;
|
||||
|
||||
procedure TPath.Assign(APath: TPath);
|
||||
begin
|
||||
Len := APath.Len;
|
||||
Points := APath.Points;
|
||||
PointsEnd := APath.PointsEnd;
|
||||
CurPoint := APath.CurPoint;
|
||||
Pen := APath.Pen;
|
||||
Brush := APath.Brush;
|
||||
Len := ASource.Len;
|
||||
Points := ASource.Points;
|
||||
PointsEnd := ASource.PointsEnd;
|
||||
CurPoint := ASource.CurPoint;
|
||||
Pen := ASource.Pen;
|
||||
Brush := ASource.Brush;
|
||||
end;
|
||||
|
||||
procedure TPath.PrepareForSequentialReading;
|
||||
|
@ -10,23 +10,22 @@ uses
|
||||
Classes, SysUtils, Math,
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
Graphics, LCLIntf,
|
||||
{$else}
|
||||
fpcanvas,
|
||||
{$endif}
|
||||
fpcanvas,
|
||||
fpimage,
|
||||
fpvectorial;
|
||||
|
||||
procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
|
||||
{$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
|
||||
ADest: TFPCustomCanvas;
|
||||
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||
procedure DrawFPVPathsToCanvas(ASource: TvVectorialDocument;
|
||||
{$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
|
||||
procedure DrawFPVPathToCanvas(ASource: TvVectorialDocument; CurPath: TPath;
|
||||
ADest: TFPCustomCanvas;
|
||||
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||
procedure DrawFPVEntitiesToCanvas(ASource: TvVectorialDocument;
|
||||
{$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
|
||||
procedure DrawFPVEntityToCanvas(ASource: TvVectorialDocument; CurEntity: TvEntity;
|
||||
ADest: TFPCustomCanvas;
|
||||
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||
procedure DrawFPVTextToCanvas(ASource: TvVectorialDocument;
|
||||
{$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
|
||||
procedure DrawFPVTextToCanvas(ASource: TvVectorialDocument; CurText: TvText;
|
||||
ADest: TFPCustomCanvas;
|
||||
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||
|
||||
implementation
|
||||
@ -47,17 +46,16 @@ begin
|
||||
end;
|
||||
|
||||
procedure DrawRotatedEllipse(
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
ADest: TCanvas;
|
||||
{$else}
|
||||
ADest: TFPCustomCanvas;
|
||||
{$endif}
|
||||
CurEllipse: TvEllipse;
|
||||
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||
var
|
||||
PointList: array[0..6] of TPoint;
|
||||
f: TPoint;
|
||||
dk, x1, x2, y1, y2: Integer;
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
ALCLDest: TCanvas absolute ADest;
|
||||
{$endif}
|
||||
begin
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
CurEllipse.CalculateBoundingRectangle();
|
||||
@ -82,7 +80,7 @@ begin
|
||||
// Conrollpoint of secondpart endpoint
|
||||
PointList[6] := PointList[0]; // Endpoint of
|
||||
// Back to the startpoint
|
||||
ADest.PolyBezier(Pointlist[0]);
|
||||
ALCLDest.PolyBezier(Pointlist[0]);
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
@ -102,24 +100,32 @@ end;
|
||||
}
|
||||
{.$define FPVECTORIAL_TOCANVAS_DEBUG}
|
||||
procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
|
||||
{$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
|
||||
ADest: TFPCustomCanvas;
|
||||
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||
var
|
||||
i: Integer;
|
||||
CurEntity: TvEntity;
|
||||
begin
|
||||
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
|
||||
WriteLn(':>DrawFPVectorialToCanvas');
|
||||
{$endif}
|
||||
|
||||
DrawFPVPathsToCanvas(ASource, ADest, ADestX, ADestY, AMulX, AMulY);
|
||||
DrawFPVEntitiesToCanvas(ASource, ADest, ADestX, ADestY, AMulX, AMulY);
|
||||
DrawFPVTextToCanvas(ASource, ADest, ADestX, ADestY, AMulX, AMulY);
|
||||
for i := 0 to ASource.GetEntitiesCount - 1 do
|
||||
begin
|
||||
CurEntity := ASource.GetEntity(i);
|
||||
|
||||
if CurEntity is TPath then DrawFPVPathToCanvas(ASource, TPath(CurEntity), ADest, ADestX, ADestY, AMulX, AMulY)
|
||||
else if CurEntity is TvText then DrawFPVTextToCanvas(ASource, TvText(CurEntity), ADest, ADestX, ADestY, AMulX, AMulY)
|
||||
else DrawFPVEntityToCanvas(ASource, CurEntity, ADest, ADestX, ADestY, AMulX, AMulY);
|
||||
end;
|
||||
|
||||
{$ifdef FPVECTORIALDEBUG}
|
||||
WriteLn(':<DrawFPVectorialToCanvas');
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
procedure DrawFPVPathsToCanvas(ASource: TvVectorialDocument;
|
||||
{$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
|
||||
procedure DrawFPVPathToCanvas(ASource: TvVectorialDocument; CurPath: TPath;
|
||||
ADest: TFPCustomCanvas;
|
||||
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||
|
||||
function CoordToCanvasX(ACoord: Double): Integer;
|
||||
@ -133,9 +139,8 @@ procedure DrawFPVPathsToCanvas(ASource: TvVectorialDocument;
|
||||
end;
|
||||
|
||||
var
|
||||
i, j, k: Integer;
|
||||
j, k: Integer;
|
||||
PosX, PosY: Integer; // Not modified by ADestX, etc
|
||||
CurPath: TPath;
|
||||
CurSegment: TPathSegment;
|
||||
Cur2DSegment: T2DSegment absolute CurSegment;
|
||||
Cur2DBSegment: T2DBezierSegment absolute CurSegment;
|
||||
@ -150,86 +155,80 @@ begin
|
||||
|
||||
ADest.MoveTo(ADestX, ADestY);
|
||||
|
||||
// Draws all paths
|
||||
for i := 0 to ASource.PathCount - 1 do
|
||||
CurPath.PrepareForSequentialReading;
|
||||
|
||||
// Set the path Pen and Brush options
|
||||
ADest.Pen.Style := CurPath.Pen.Style;
|
||||
ADest.Pen.Width := CurPath.Pen.Width;
|
||||
ADest.Brush.Style := CurPath.Brush.Style;
|
||||
ADest.Pen.FPColor := CurPath.Pen.Color;
|
||||
ADest.Brush.FPColor := CurPath.Brush.Color;
|
||||
|
||||
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
|
||||
Write(Format('[Path] ID=%d', [i]));
|
||||
{$endif}
|
||||
|
||||
for j := 0 to CurPath.Len - 1 do
|
||||
begin
|
||||
//WriteLn('i = ', i);
|
||||
CurPath := ASource.Paths[i];
|
||||
CurPath.PrepareForSequentialReading;
|
||||
//WriteLn('j = ', j);
|
||||
CurSegment := TPathSegment(CurPath.Next());
|
||||
|
||||
// Set the path Pen and Brush options
|
||||
ADest.Pen.Style := CurPath.Pen.Style;
|
||||
ADest.Pen.Width := CurPath.Pen.Width;
|
||||
ADest.Brush.Style := CurPath.Brush.Style;
|
||||
ADest.Pen.FPColor := CurPath.Pen.Color;
|
||||
ADest.Brush.FPColor := CurPath.Brush.Color;
|
||||
|
||||
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
|
||||
Write(Format('[Path] ID=%d', [i]));
|
||||
{$endif}
|
||||
|
||||
for j := 0 to CurPath.Len - 1 do
|
||||
case CurSegment.SegmentType of
|
||||
stMoveTo:
|
||||
begin
|
||||
//WriteLn('j = ', j);
|
||||
CurSegment := TPathSegment(CurPath.Next());
|
||||
|
||||
case CurSegment.SegmentType of
|
||||
stMoveTo:
|
||||
begin
|
||||
ADest.MoveTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
|
||||
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
|
||||
Write(Format(' M%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
|
||||
{$endif}
|
||||
end;
|
||||
// This element can override temporarely the Pen
|
||||
st2DLineWithPen:
|
||||
begin
|
||||
ADest.Pen.FPColor := T2DSegmentWithPen(Cur2DSegment).Pen.Color;
|
||||
|
||||
ADest.LineTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
|
||||
|
||||
ADest.Pen.FPColor := CurPath.Pen.Color;
|
||||
|
||||
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
|
||||
Write(Format(' L%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
|
||||
{$endif}
|
||||
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
|
||||
lines between this parts }
|
||||
st2DBezier, st3DBezier:
|
||||
begin
|
||||
CurveLength :=
|
||||
Round(sqrt(sqr(Cur2DBSegment.X3 - PosX) + sqr(Cur2DBSegment.Y3 - PosY))) +
|
||||
Round(sqrt(sqr(Cur2DBSegment.X2 - Cur2DBSegment.X3) + sqr(Cur2DBSegment.Y2 - Cur2DBSegment.Y3))) +
|
||||
Round(sqrt(sqr(Cur2DBSegment.X - Cur2DBSegment.X3) + sqr(Cur2DBSegment.Y - Cur2DBSegment.Y3)));
|
||||
|
||||
for k := 1 to CurveLength do
|
||||
begin
|
||||
t := k / CurveLength;
|
||||
CurX := Round(sqr(1 - t) * (1 - t) * PosX + 3 * t * sqr(1 - t) * Cur2DBSegment.X2 + 3 * t * t * (1 - t) * Cur2DBSegment.X3 + t * t * t * Cur2DBSegment.X);
|
||||
CurY := Round(sqr(1 - t) * (1 - t) * PosY + 3 * t * sqr(1 - t) * Cur2DBSegment.Y2 + 3 * t * t * (1 - t) * Cur2DBSegment.Y3 + t * t * t * Cur2DBSegment.Y);
|
||||
ADest.LineTo(CoordToCanvasX(CurX), CoordToCanvasY(CurY));
|
||||
end;
|
||||
PosX := Round(Cur2DBSegment.X);
|
||||
PosY := Round(Cur2DBSegment.Y);
|
||||
end;
|
||||
end;
|
||||
ADest.MoveTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
|
||||
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
|
||||
Write(Format(' M%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
|
||||
{$endif}
|
||||
end;
|
||||
// This element can override temporarely the Pen
|
||||
st2DLineWithPen:
|
||||
begin
|
||||
ADest.Pen.FPColor := T2DSegmentWithPen(Cur2DSegment).Pen.Color;
|
||||
|
||||
ADest.LineTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
|
||||
|
||||
ADest.Pen.FPColor := CurPath.Pen.Color;
|
||||
|
||||
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
|
||||
Write(Format(' L%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
|
||||
{$endif}
|
||||
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
|
||||
lines between this parts }
|
||||
st2DBezier, st3DBezier:
|
||||
begin
|
||||
CurveLength :=
|
||||
Round(sqrt(sqr(Cur2DBSegment.X3 - PosX) + sqr(Cur2DBSegment.Y3 - PosY))) +
|
||||
Round(sqrt(sqr(Cur2DBSegment.X2 - Cur2DBSegment.X3) + sqr(Cur2DBSegment.Y2 - Cur2DBSegment.Y3))) +
|
||||
Round(sqrt(sqr(Cur2DBSegment.X - Cur2DBSegment.X3) + sqr(Cur2DBSegment.Y - Cur2DBSegment.Y3)));
|
||||
|
||||
for k := 1 to CurveLength do
|
||||
begin
|
||||
t := k / CurveLength;
|
||||
CurX := Round(sqr(1 - t) * (1 - t) * PosX + 3 * t * sqr(1 - t) * Cur2DBSegment.X2 + 3 * t * t * (1 - t) * Cur2DBSegment.X3 + t * t * t * Cur2DBSegment.X);
|
||||
CurY := Round(sqr(1 - t) * (1 - t) * PosY + 3 * t * sqr(1 - t) * Cur2DBSegment.Y2 + 3 * t * t * (1 - t) * Cur2DBSegment.Y3 + t * t * t * Cur2DBSegment.Y);
|
||||
ADest.LineTo(CoordToCanvasX(CurX), CoordToCanvasY(CurY));
|
||||
end;
|
||||
PosX := Round(Cur2DBSegment.X);
|
||||
PosY := Round(Cur2DBSegment.Y);
|
||||
end;
|
||||
end;
|
||||
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
|
||||
WriteLn('');
|
||||
{$endif}
|
||||
end;
|
||||
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
|
||||
WriteLn('');
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
procedure DrawFPVEntitiesToCanvas(ASource: TvVectorialDocument;
|
||||
{$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
|
||||
procedure DrawFPVEntityToCanvas(ASource: TvVectorialDocument; CurEntity: TvEntity;
|
||||
ADest: TFPCustomCanvas;
|
||||
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||
|
||||
function CoordToCanvasX(ACoord: Double): Integer;
|
||||
@ -244,8 +243,10 @@ procedure DrawFPVEntitiesToCanvas(ASource: TvVectorialDocument;
|
||||
|
||||
var
|
||||
i: Integer;
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
ALCLDest: TCanvas absolute ADest;
|
||||
{$endif}
|
||||
// For entities
|
||||
CurEntity: TvEntity;
|
||||
CurCircle: TvCircle;
|
||||
CurEllipse: TvEllipse;
|
||||
//
|
||||
@ -258,192 +259,178 @@ var
|
||||
Points: array of TPoint;
|
||||
UpperDim, LowerDim: T3DPoint;
|
||||
begin
|
||||
// Draws all entities
|
||||
for i := 0 to ASource.GetEntityCount - 1 do
|
||||
ADest.Brush.Style := CurEntity.Brush.Style;
|
||||
ADest.Pen.Style := CurEntity.Pen.Style;
|
||||
ADest.Pen.FPColor := CurEntity.Pen.Color;
|
||||
ADest.Brush.FPColor := CurEntity.Brush.Color;
|
||||
|
||||
if CurEntity is TvCircle then
|
||||
begin
|
||||
CurEntity := ASource.GetEntity(i);
|
||||
|
||||
ADest.Brush.Style := CurEntity.Brush.Style;
|
||||
ADest.Pen.Style := CurEntity.Pen.Style;
|
||||
ADest.Pen.FPColor := CurEntity.Pen.Color;
|
||||
ADest.Brush.FPColor := CurEntity.Brush.Color;
|
||||
|
||||
if CurEntity is TvCircle then
|
||||
CurCircle := CurEntity as TvCircle;
|
||||
ADest.Ellipse(
|
||||
CoordToCanvasX(CurCircle.CenterX - CurCircle.Radius),
|
||||
CoordToCanvasY(CurCircle.CenterY - CurCircle.Radius),
|
||||
CoordToCanvasX(CurCircle.CenterX + CurCircle.Radius),
|
||||
CoordToCanvasY(CurCircle.CenterY + CurCircle.Radius)
|
||||
);
|
||||
end
|
||||
else if CurEntity is TvEllipse then
|
||||
begin
|
||||
CurEllipse := CurEntity as TvEllipse;
|
||||
DrawRotatedEllipse(ADest, CurEllipse);
|
||||
end
|
||||
else if CurEntity is TvCircularArc then
|
||||
begin
|
||||
CurArc := CurEntity as TvCircularArc;
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
// ToDo: Consider a X axis inversion
|
||||
// If the Y axis is inverted, then we need to mirror our angles as well
|
||||
BoundsLeft := CoordToCanvasX(CurArc.CenterX - CurArc.Radius);
|
||||
BoundsTop := CoordToCanvasY(CurArc.CenterY - CurArc.Radius);
|
||||
BoundsRight := CoordToCanvasX(CurArc.CenterX + CurArc.Radius);
|
||||
BoundsBottom := CoordToCanvasY(CurArc.CenterY + CurArc.Radius);
|
||||
{if AMulY > 0 then
|
||||
begin}
|
||||
FinalStartAngle := CurArc.StartAngle;
|
||||
FinalEndAngle := CurArc.EndAngle;
|
||||
{end
|
||||
else // AMulY is negative
|
||||
begin
|
||||
CurCircle := CurEntity as TvCircle;
|
||||
ADest.Ellipse(
|
||||
CoordToCanvasX(CurCircle.CenterX - CurCircle.Radius),
|
||||
CoordToCanvasY(CurCircle.CenterY - CurCircle.Radius),
|
||||
CoordToCanvasX(CurCircle.CenterX + CurCircle.Radius),
|
||||
CoordToCanvasY(CurCircle.CenterY + CurCircle.Radius)
|
||||
);
|
||||
end
|
||||
else if CurEntity is TvEllipse then
|
||||
// Inverting the angles generates the correct result for Y axis inversion
|
||||
if CurArc.EndAngle = 0 then FinalStartAngle := 0
|
||||
else FinalStartAngle := 360 - 1* CurArc.EndAngle;
|
||||
if CurArc.StartAngle = 0 then FinalEndAngle := 0
|
||||
else FinalEndAngle := 360 - 1* CurArc.StartAngle;
|
||||
end;}
|
||||
IntStartAngle := Round(16*FinalStartAngle);
|
||||
IntAngleLength := Round(16*(FinalEndAngle - FinalStartAngle));
|
||||
// On Gtk2 and Carbon, the Left really needs to be to the Left of the Right position
|
||||
// The same for the Top and Bottom
|
||||
// On Windows it works fine either way
|
||||
// On Gtk2 if the positions are inverted then the arcs are screwed up
|
||||
// In Carbon if the positions are inverted, then the arc is inverted
|
||||
if BoundsLeft > BoundsRight then
|
||||
begin
|
||||
CurEllipse := CurEntity as TvEllipse;
|
||||
DrawRotatedEllipse(ADest, CurEllipse);
|
||||
end
|
||||
else if CurEntity is TvCircularArc then
|
||||
IntTmp := BoundsLeft;
|
||||
BoundsLeft := BoundsRight;
|
||||
BoundsRight := IntTmp;
|
||||
end;
|
||||
if BoundsTop > BoundsBottom then
|
||||
begin
|
||||
CurArc := CurEntity as TvCircularArc;
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
// ToDo: Consider a X axis inversion
|
||||
// If the Y axis is inverted, then we need to mirror our angles as well
|
||||
BoundsLeft := CoordToCanvasX(CurArc.CenterX - CurArc.Radius);
|
||||
BoundsTop := CoordToCanvasY(CurArc.CenterY - CurArc.Radius);
|
||||
BoundsRight := CoordToCanvasX(CurArc.CenterX + CurArc.Radius);
|
||||
BoundsBottom := CoordToCanvasY(CurArc.CenterY + CurArc.Radius);
|
||||
{if AMulY > 0 then
|
||||
begin}
|
||||
FinalStartAngle := CurArc.StartAngle;
|
||||
FinalEndAngle := CurArc.EndAngle;
|
||||
{end
|
||||
else // AMulY is negative
|
||||
begin
|
||||
// Inverting the angles generates the correct result for Y axis inversion
|
||||
if CurArc.EndAngle = 0 then FinalStartAngle := 0
|
||||
else FinalStartAngle := 360 - 1* CurArc.EndAngle;
|
||||
if CurArc.StartAngle = 0 then FinalEndAngle := 0
|
||||
else FinalEndAngle := 360 - 1* CurArc.StartAngle;
|
||||
end;}
|
||||
IntStartAngle := Round(16*FinalStartAngle);
|
||||
IntAngleLength := Round(16*(FinalEndAngle - FinalStartAngle));
|
||||
// On Gtk2 and Carbon, the Left really needs to be to the Left of the Right position
|
||||
// The same for the Top and Bottom
|
||||
// On Windows it works fine either way
|
||||
// On Gtk2 if the positions are inverted then the arcs are screwed up
|
||||
// In Carbon if the positions are inverted, then the arc is inverted
|
||||
if BoundsLeft > BoundsRight then
|
||||
begin
|
||||
IntTmp := BoundsLeft;
|
||||
BoundsLeft := BoundsRight;
|
||||
BoundsRight := IntTmp;
|
||||
end;
|
||||
if BoundsTop > BoundsBottom then
|
||||
begin
|
||||
IntTmp := BoundsTop;
|
||||
BoundsTop := BoundsBottom;
|
||||
BoundsBottom := IntTmp;
|
||||
end;
|
||||
// Arc(ALeft, ATop, ARight, ABottom, Angle16Deg, Angle16DegLength: Integer);
|
||||
{$ifdef FPVECTORIALDEBUG}
|
||||
WriteLn(Format('Drawing Arc Center=%f,%f Radius=%f StartAngle=%f AngleLength=%f',
|
||||
[CurArc.CenterX, CurArc.CenterY, CurArc.Radius, IntStartAngle/16, IntAngleLength/16]));
|
||||
{$endif}
|
||||
ADest.Pen.FPColor := CurArc.Pen.Color;
|
||||
ADest.Arc(
|
||||
BoundsLeft, BoundsTop, BoundsRight, BoundsBottom,
|
||||
IntStartAngle, IntAngleLength
|
||||
);
|
||||
ADest.Pen.Color := clBlack;
|
||||
// Debug info
|
||||
IntTmp := BoundsTop;
|
||||
BoundsTop := BoundsBottom;
|
||||
BoundsBottom := IntTmp;
|
||||
end;
|
||||
// Arc(ALeft, ATop, ARight, ABottom, Angle16Deg, Angle16DegLength: Integer);
|
||||
{$ifdef FPVECTORIALDEBUG}
|
||||
WriteLn(Format('Drawing Arc Center=%f,%f Radius=%f StartAngle=%f AngleLength=%f',
|
||||
[CurArc.CenterX, CurArc.CenterY, CurArc.Radius, IntStartAngle/16, IntAngleLength/16]));
|
||||
{$endif}
|
||||
ADest.Pen.FPColor := CurArc.Pen.Color;
|
||||
ALCLDest.Arc(
|
||||
BoundsLeft, BoundsTop, BoundsRight, BoundsBottom,
|
||||
IntStartAngle, IntAngleLength
|
||||
);
|
||||
ADest.Pen.FPColor := colBlack;
|
||||
// Debug info
|
||||
// {$define FPVECTORIALDEBUG}
|
||||
// {$ifdef FPVECTORIALDEBUG}
|
||||
// WriteLn(Format('Drawing Arc x1y1=%d,%d x2y2=%d,%d start=%d end=%d',
|
||||
// [BoundsLeft, BoundsTop, BoundsRight, BoundsBottom, IntStartAngle, IntAngleLength]));
|
||||
// {$endif}
|
||||
{ ADest.TextOut(CoordToCanvasX(CurArc.CenterX), CoordToCanvasY(CurArc.CenterY),
|
||||
Format('R=%d S=%d L=%d', [Round(CurArc.Radius*AMulX), Round(FinalStartAngle),
|
||||
Abs(Round((FinalEndAngle - FinalStartAngle)))]));
|
||||
ADest.Pen.Color := TColor($DDDDDD);
|
||||
ADest.Rectangle(
|
||||
BoundsLeft, BoundsTop, BoundsRight, BoundsBottom);
|
||||
ADest.Pen.Color := clBlack;}
|
||||
{$endif}
|
||||
end
|
||||
else if CurEntity is TvAlignedDimension then
|
||||
Format('R=%d S=%d L=%d', [Round(CurArc.Radius*AMulX), Round(FinalStartAngle),
|
||||
Abs(Round((FinalEndAngle - FinalStartAngle)))]));
|
||||
ADest.Pen.Color := TColor($DDDDDD);
|
||||
ADest.Rectangle(
|
||||
BoundsLeft, BoundsTop, BoundsRight, BoundsBottom);
|
||||
ADest.Pen.Color := clBlack;}
|
||||
{$endif}
|
||||
end
|
||||
else if CurEntity is TvAlignedDimension then
|
||||
begin
|
||||
CurDim := CurEntity as TvAlignedDimension;
|
||||
//
|
||||
// Draws this shape:
|
||||
// vertical horizontal
|
||||
// ___
|
||||
// | | or ---| X cm
|
||||
// | --|
|
||||
// Which marks the dimension
|
||||
ADest.MoveTo(CoordToCanvasX(CurDim.BaseRight.X), CoordToCanvasY(CurDim.BaseRight.Y));
|
||||
ADest.LineTo(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y));
|
||||
ADest.LineTo(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y));
|
||||
ADest.LineTo(CoordToCanvasX(CurDim.BaseLeft.X), CoordToCanvasY(CurDim.BaseLeft.Y));
|
||||
// Now the arrows
|
||||
// horizontal
|
||||
SetLength(Points, 3);
|
||||
if CurDim.DimensionRight.Y = CurDim.DimensionLeft.Y then
|
||||
begin
|
||||
CurDim := CurEntity as TvAlignedDimension;
|
||||
//
|
||||
// Draws this shape:
|
||||
// vertical horizontal
|
||||
// ___
|
||||
// | | or ---| X cm
|
||||
// | --|
|
||||
// Which marks the dimension
|
||||
ADest.MoveTo(CoordToCanvasX(CurDim.BaseRight.X), CoordToCanvasY(CurDim.BaseRight.Y));
|
||||
ADest.LineTo(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y));
|
||||
ADest.LineTo(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y));
|
||||
ADest.LineTo(CoordToCanvasX(CurDim.BaseLeft.X), CoordToCanvasY(CurDim.BaseLeft.Y));
|
||||
// Now the arrows
|
||||
// horizontal
|
||||
SetLength(Points, 3);
|
||||
if CurDim.DimensionRight.Y = CurDim.DimensionLeft.Y then
|
||||
ADest.Brush.FPColor := colBlack;
|
||||
ADest.Brush.Style := bsSolid;
|
||||
// Left arrow
|
||||
Points[0] := Point(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y));
|
||||
Points[1] := Point(Points[0].X + 7, Points[0].Y - 3);
|
||||
Points[2] := Point(Points[0].X + 7, Points[0].Y + 3);
|
||||
ADest.Polygon(Points);
|
||||
// Right arrow
|
||||
Points[0] := Point(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y));
|
||||
Points[1] := Point(Points[0].X - 7, Points[0].Y - 3);
|
||||
Points[2] := Point(Points[0].X - 7, Points[0].Y + 3);
|
||||
ADest.Polygon(Points);
|
||||
ADest.Brush.Style := bsClear;
|
||||
// Dimension text
|
||||
Points[0].X := CoordToCanvasX((CurDim.DimensionLeft.X+CurDim.DimensionRight.X)/2);
|
||||
Points[0].Y := CoordToCanvasY(CurDim.DimensionLeft.Y);
|
||||
LowerDim.X := CurDim.DimensionRight.X-CurDim.DimensionLeft.X;
|
||||
ADest.Font.Size := 10;
|
||||
ADest.TextOut(Points[0].X, Points[0].Y, Format('%.1f', [LowerDim.X]));
|
||||
end
|
||||
else
|
||||
begin
|
||||
ADest.Brush.FPColor := colBlack;
|
||||
ADest.Brush.Style := bsSolid;
|
||||
// There is no upper/lower preference for DimensionLeft/Right, so we need to check
|
||||
if CurDim.DimensionLeft.Y > CurDim.DimensionRight.Y then
|
||||
begin
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
ADest.Brush.Color := clBlack;
|
||||
{$else}
|
||||
ADest.Brush.FPColor := colBlack;
|
||||
{$endif}
|
||||
ADest.Brush.Style := bsSolid;
|
||||
// Left arrow
|
||||
Points[0] := Point(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y));
|
||||
Points[1] := Point(Points[0].X + 7, Points[0].Y - 3);
|
||||
Points[2] := Point(Points[0].X + 7, Points[0].Y + 3);
|
||||
ADest.Polygon(Points);
|
||||
// Right arrow
|
||||
Points[0] := Point(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y));
|
||||
Points[1] := Point(Points[0].X - 7, Points[0].Y - 3);
|
||||
Points[2] := Point(Points[0].X - 7, Points[0].Y + 3);
|
||||
ADest.Polygon(Points);
|
||||
ADest.Brush.Style := bsClear;
|
||||
// Dimension text
|
||||
Points[0].X := CoordToCanvasX((CurDim.DimensionLeft.X+CurDim.DimensionRight.X)/2);
|
||||
Points[0].Y := CoordToCanvasY(CurDim.DimensionLeft.Y);
|
||||
LowerDim.X := CurDim.DimensionRight.X-CurDim.DimensionLeft.X;
|
||||
ADest.Font.Size := 10;
|
||||
ADest.TextOut(Points[0].X, Points[0].Y, Format('%.1f', [LowerDim.X]));
|
||||
UpperDim := CurDim.DimensionLeft;
|
||||
LowerDim := CurDim.DimensionRight;
|
||||
end
|
||||
else
|
||||
begin
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
ADest.Brush.Color := clBlack;
|
||||
{$else}
|
||||
ADest.Brush.FPColor := colBlack;
|
||||
{$endif}
|
||||
ADest.Brush.Style := bsSolid;
|
||||
// There is no upper/lower preference for DimensionLeft/Right, so we need to check
|
||||
if CurDim.DimensionLeft.Y > CurDim.DimensionRight.Y then
|
||||
begin
|
||||
UpperDim := CurDim.DimensionLeft;
|
||||
LowerDim := CurDim.DimensionRight;
|
||||
end
|
||||
else
|
||||
begin
|
||||
UpperDim := CurDim.DimensionRight;
|
||||
LowerDim := CurDim.DimensionLeft;
|
||||
end;
|
||||
// Upper arrow
|
||||
Points[0] := Point(CoordToCanvasX(UpperDim.X), CoordToCanvasY(UpperDim.Y));
|
||||
Points[1] := Point(Points[0].X + Round(AMulX), Points[0].Y - Round(AMulY*3));
|
||||
Points[2] := Point(Points[0].X - Round(AMulX), Points[0].Y - Round(AMulY*3));
|
||||
ADest.Polygon(Points);
|
||||
// Lower arrow
|
||||
Points[0] := Point(CoordToCanvasX(LowerDim.X), CoordToCanvasY(LowerDim.Y));
|
||||
Points[1] := Point(Points[0].X + Round(AMulX), Points[0].Y + Round(AMulY*3));
|
||||
Points[2] := Point(Points[0].X - Round(AMulX), Points[0].Y + Round(AMulY*3));
|
||||
ADest.Polygon(Points);
|
||||
ADest.Brush.Style := bsClear;
|
||||
// Dimension text
|
||||
Points[0].X := CoordToCanvasX(CurDim.DimensionLeft.X);
|
||||
Points[0].Y := CoordToCanvasY((CurDim.DimensionLeft.Y+CurDim.DimensionRight.Y)/2);
|
||||
LowerDim.Y := CurDim.DimensionRight.Y-CurDim.DimensionLeft.Y;
|
||||
if LowerDim.Y < 0 then LowerDim.Y := -1 * LowerDim.Y;
|
||||
ADest.Font.Size := 10;
|
||||
ADest.TextOut(Points[0].X, Points[0].Y, Format('%.1f', [LowerDim.Y]));
|
||||
UpperDim := CurDim.DimensionRight;
|
||||
LowerDim := CurDim.DimensionLeft;
|
||||
end;
|
||||
SetLength(Points, 0);
|
||||
{ // Debug info
|
||||
ADest.TextOut(CoordToCanvasX(CurDim.BaseRight.X), CoordToCanvasY(CurDim.BaseRight.Y), 'BR');
|
||||
ADest.TextOut(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y), 'DR');
|
||||
ADest.TextOut(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y), 'DL');
|
||||
ADest.TextOut(CoordToCanvasX(CurDim.BaseLeft.X), CoordToCanvasY(CurDim.BaseLeft.Y), 'BL');}
|
||||
// Upper arrow
|
||||
Points[0] := Point(CoordToCanvasX(UpperDim.X), CoordToCanvasY(UpperDim.Y));
|
||||
Points[1] := Point(Points[0].X + Round(AMulX), Points[0].Y - Round(AMulY*3));
|
||||
Points[2] := Point(Points[0].X - Round(AMulX), Points[0].Y - Round(AMulY*3));
|
||||
ADest.Polygon(Points);
|
||||
// Lower arrow
|
||||
Points[0] := Point(CoordToCanvasX(LowerDim.X), CoordToCanvasY(LowerDim.Y));
|
||||
Points[1] := Point(Points[0].X + Round(AMulX), Points[0].Y + Round(AMulY*3));
|
||||
Points[2] := Point(Points[0].X - Round(AMulX), Points[0].Y + Round(AMulY*3));
|
||||
ADest.Polygon(Points);
|
||||
ADest.Brush.Style := bsClear;
|
||||
// Dimension text
|
||||
Points[0].X := CoordToCanvasX(CurDim.DimensionLeft.X);
|
||||
Points[0].Y := CoordToCanvasY((CurDim.DimensionLeft.Y+CurDim.DimensionRight.Y)/2);
|
||||
LowerDim.Y := CurDim.DimensionRight.Y-CurDim.DimensionLeft.Y;
|
||||
if LowerDim.Y < 0 then LowerDim.Y := -1 * LowerDim.Y;
|
||||
ADest.Font.Size := 10;
|
||||
ADest.TextOut(Points[0].X, Points[0].Y, Format('%.1f', [LowerDim.Y]));
|
||||
end;
|
||||
SetLength(Points, 0);
|
||||
{ // Debug info
|
||||
ADest.TextOut(CoordToCanvasX(CurDim.BaseRight.X), CoordToCanvasY(CurDim.BaseRight.Y), 'BR');
|
||||
ADest.TextOut(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y), 'DR');
|
||||
ADest.TextOut(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y), 'DL');
|
||||
ADest.TextOut(CoordToCanvasX(CurDim.BaseLeft.X), CoordToCanvasY(CurDim.BaseLeft.Y), 'BL');}
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure DrawFPVTextToCanvas(ASource: TvVectorialDocument;
|
||||
{$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
|
||||
procedure DrawFPVTextToCanvas(ASource: TvVectorialDocument; CurText: TvText;
|
||||
ADest: TFPCustomCanvas;
|
||||
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||
|
||||
function CoordToCanvasX(ACoord: Double): Integer;
|
||||
@ -458,29 +445,20 @@ procedure DrawFPVTextToCanvas(ASource: TvVectorialDocument;
|
||||
|
||||
var
|
||||
i: Integer;
|
||||
// For text
|
||||
CurText: TvText;
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
ALCLDest: TCanvas absolute ADest;
|
||||
{$endif}
|
||||
//
|
||||
LowerDim: T3DPoint;
|
||||
begin
|
||||
// Draws all text
|
||||
for i := 0 to ASource.GetTextCount - 1 do
|
||||
begin
|
||||
CurText := ASource.GetText(i);
|
||||
ADest.Font.Size := Round(AmulX * CurText.Font.Size);
|
||||
ADest.Pen.Style := psSolid;
|
||||
ADest.Pen.FPColor := colBlack;
|
||||
ADest.Brush.Style := bsClear;
|
||||
ALCLDest.Font.Orientation := Round(CurText.Font.Orientation * 16);
|
||||
|
||||
ADest.Font.Size := Round(AmulX * CurText.Font.Size);
|
||||
ADest.Pen.Style := psSolid;
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
ADest.Pen.Color := clBlack;
|
||||
{$else}
|
||||
ADest.Pen.FPColor := colBlack;
|
||||
{$endif}
|
||||
ADest.Brush.Style := bsClear;
|
||||
ADest.Font.Orientation := Round(CurText.Font.Orientation * 16);
|
||||
|
||||
LowerDim.Y := CurText.Y + CurText.Font.Size;
|
||||
ADest.TextOut(CoordToCanvasX(CurText.X), CoordToCanvasY(LowerDim.Y), CurText.Value);
|
||||
end;
|
||||
LowerDim.Y := CurText.Y + CurText.Font.Size;
|
||||
ADest.TextOut(CoordToCanvasX(CurText.X), CoordToCanvasY(LowerDim.Y), CurText.Value);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -29,6 +29,7 @@ function FPColorToRGBHexString(AColor: TFPColor): string;
|
||||
function RGBToFPColor(AR, AG, AB: byte): TFPColor; inline;
|
||||
// Other routine
|
||||
function CanvasCoordsToFPVectorial(AY: Integer; AHeight: Integer): Integer; inline;
|
||||
function CanvasTextPosToFPVectorial(AY: Integer; ACanvasHeight, ATextHeight: Integer): Integer;
|
||||
function SeparateString(AString: string; ASeparator: char): T10Strings;
|
||||
|
||||
implementation
|
||||
@ -54,12 +55,26 @@ end;
|
||||
points upwards in FPVectorial and downwards in TCanvas.
|
||||
The X axis doesn't change. The fix is trivial and requires only the Height of
|
||||
the Canvas as extra info.
|
||||
|
||||
@param AHeight Should receive TCanvas.Height
|
||||
}
|
||||
function CanvasCoordsToFPVectorial(AY: Integer; AHeight: Integer): Integer; inline;
|
||||
begin
|
||||
Result := AHeight - AY;
|
||||
end;
|
||||
|
||||
{@@
|
||||
LCL Text is positioned based on the top-left corner of the text.
|
||||
Besides that, one also needs to take the general coordinate change into account too.
|
||||
|
||||
@param ACanvasHeight Should receive TCanvas.Height
|
||||
@param ATextHeight Should receive TFont.Size
|
||||
}
|
||||
function CanvasTextPosToFPVectorial(AY: Integer; ACanvasHeight, ATextHeight: Integer): Integer;
|
||||
begin
|
||||
Result := CanvasCoordsToFPVectorial(AY, ACanvasHeight) - ATextHeight;
|
||||
end;
|
||||
|
||||
{@@
|
||||
Reads a string and separates it in substring
|
||||
using ASeparator to delimite them.
|
||||
|
@ -23,9 +23,9 @@ type
|
||||
FPointSeparator, FCommaSeparator: TFormatSettings;
|
||||
procedure WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
|
||||
procedure WriteDocumentName(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 WriteText(AStrings: TStrings; lText: TvText; AData: TvVectorialDocument);
|
||||
procedure WriteEntities(AStrings: TStrings; AData: TvVectorialDocument);
|
||||
procedure ConvertFPVCoordinatesToSVGCoordinates(
|
||||
const AData: TvVectorialDocument;
|
||||
const ASrcX, ASrcY: Double; var ADestX, ADestY: double);
|
||||
@ -61,19 +61,6 @@ begin
|
||||
AStrings.Add(' sodipodi:docname="New document 1">');
|
||||
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
|
||||
hardcode a DPI value for the screen, which is usually 72.
|
||||
@ -227,43 +214,52 @@ begin
|
||||
|
||||
// Now data
|
||||
AStrings.Add(' <g id="layer1">');
|
||||
WritePaths(AStrings, AData);
|
||||
WriteTexts(AStrings, AData);
|
||||
WriteEntities(AStrings, AData);
|
||||
AStrings.Add(' </g>');
|
||||
|
||||
// finalization
|
||||
AStrings.Add('</svg>');
|
||||
end;
|
||||
|
||||
procedure TvSVGVectorialWriter.WriteTexts(AStrings: TStrings; AData: TvVectorialDocument);
|
||||
procedure TvSVGVectorialWriter.WriteText(AStrings: TStrings; lText: TvText; AData: TvVectorialDocument);
|
||||
var
|
||||
i, j, FontSize: Integer;
|
||||
TextStr, FontName, SVGFontFamily: string;
|
||||
lText: TvText;
|
||||
PtX, PtY: double;
|
||||
begin
|
||||
for i := 0 to AData.GetTextCount() - 1 do
|
||||
begin
|
||||
TextStr := '';
|
||||
lText := AData.GetText(i);
|
||||
TextStr := '';
|
||||
|
||||
ConvertFPVCoordinatesToSVGCoordinates(
|
||||
AData, lText.X, lText.Y, PtX, PtY);
|
||||
ConvertFPVCoordinatesToSVGCoordinates(
|
||||
AData, lText.X, lText.Y, PtX, PtY);
|
||||
|
||||
TextStr := lText.Value;
|
||||
FontSize:= ceil(lText.Font.Size / FLOAT_MILIMETERS_PER_PIXEL);
|
||||
SVGFontFamily := 'Arial, sans-serif';//lText.FontName;
|
||||
TextStr := lText.Value;
|
||||
FontSize:= ceil(lText.Font.Size / FLOAT_MILIMETERS_PER_PIXEL);
|
||||
SVGFontFamily := 'Arial, sans-serif';//lText.FontName;
|
||||
|
||||
AStrings.Add(' <text ');
|
||||
AStrings.Add(' x="' + FloatToStr(PtX, FPointSeparator) + '"');
|
||||
AStrings.Add(' y="' + FloatToStr(PtY, FPointSeparator) + '"');
|
||||
AStrings.Add(' <text ');
|
||||
AStrings.Add(' x="' + FloatToStr(PtX, FPointSeparator) + '"');
|
||||
AStrings.Add(' y="' + FloatToStr(PtY, FPointSeparator) + '"');
|
||||
// AStrings.Add(' font-size="' + IntToStr(FontSize) + '"'); Doesn't seam to work, we need to use the tspan
|
||||
AStrings.Add(' font-family="' + SVGFontFamily + '">');
|
||||
AStrings.Add(' <tspan ');
|
||||
AStrings.Add(' style="font-size:' + IntToStr(FontSize) + '" ');
|
||||
AStrings.Add(' font-family="' + SVGFontFamily + '">');
|
||||
AStrings.Add(' <tspan ');
|
||||
AStrings.Add(' style="font-size:' + IntToStr(FontSize) + '" ');
|
||||
// AStrings.Add(' id="tspan2828" ');
|
||||
AStrings.Add(' >');
|
||||
AStrings.Add(TextStr + '</tspan></text>');
|
||||
AStrings.Add(' >');
|
||||
AStrings.Add(TextStr + '</tspan></text>');
|
||||
end;
|
||||
|
||||
procedure TvSVGVectorialWriter.WriteEntities(AStrings: TStrings;
|
||||
AData: TvVectorialDocument);
|
||||
var
|
||||
lEntity: TvEntity;
|
||||
i: Integer;
|
||||
begin
|
||||
for i := 0 to AData.GetEntitiesCount() - 1 do
|
||||
begin
|
||||
lEntity := AData.GetEntity(i);
|
||||
|
||||
if lEntity is TPath then WritePath(i, TPath(lEntity), AStrings, AData)
|
||||
else if lEntity is TvText then WriteText(AStrings, TvText(lEntity), AData);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
Reference in New Issue
Block a user