freebsd-ports/graphics/fpc-fpvectorial/files/patch-packages-fpvectorial-src_fpvectorial.pas
Jose Alonso Cardenas Marquez 424718714b - Update to 2.4.4
2011-06-23 05:05:29 +00:00

703 lines
19 KiB
ObjectPascal

--- packages/fpvectorial/src/fpvectorial.pas 2011/01/30 15:51:36 16850
+++ packages/fpvectorial/src/fpvectorial.pas 2011/06/17 09:52:19 17765
@@ -18,14 +18,17 @@
interface
uses
- Classes, SysUtils, Math;
+ Classes, SysUtils, Math,
+ fpcanvas, fpimage;
type
TvVectorialFormat = (
{ Multi-purpose document formats }
- vfPDF, vfPostScript, vfSVG, vfCorelDrawCDR, vfWindowsMetafileWMF,
+ vfPDF, vfSVG, vfCorelDrawCDR, vfWindowsMetafileWMF,
{ CAD formats }
vfDXF,
+ { Printing formats }
+ vfPostScript, vfEncapsulatedPostScript,
{ GCode formats }
vfGCodeAvisoCNCPrototipoV5, vfGCodeAvisoCNCPrototipoV6);
@@ -37,10 +40,45 @@
STR_SVG_EXTENSION = '.svg';
STR_CORELDRAW_EXTENSION = '.cdr';
STR_WINMETAFILE_EXTENSION = '.wmf';
+ STR_AUTOCAD_EXCHANGE_EXTENSION = '.dxf';
+ STR_ENCAPSULATEDPOSTSCRIPT_EXTENSION = '.eps';
type
+ { Pen, Brush and Font }
+
+ TvPen = record
+ Color: TFPColor;
+ Style: TFPPenStyle;
+ Width: Integer;
+ end;
+
+ TvBrush = record
+ Color: TFPColor;
+ Style: TFPBrushStyle;
+ 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;
+
+ { Coordinates and polyline segments }
+
+ T3DPoint = record
+ X, Y, Z: Double;
+ end;
+
+ P3DPoint = ^T3DPoint;
+
TSegmentType = (
- st2DLine, st2DBezier,
+ st2DLine, st2DLineWithPen, st2DBezier,
st3DLine, st3DBezier, stMoveTo);
{@@
@@ -70,6 +108,11 @@
X, Y: Double;
end;
+ T2DSegmentWithPen = class(T2DSegment)
+ public
+ Pen: TvPen;
+ end;
+
{@@
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
@@ -96,13 +139,30 @@
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
- procedure Assign(APath: TPath);
- function Count(): TPathSegment;
+ procedure Assign(ASource: TPath);
procedure PrepareForSequentialReading;
function Next(): TPathSegment;
end;
@@ -113,18 +173,11 @@
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
- FontSize: integer;
- FontName: utf8string;
Value: utf8string;
- end;
-
- {@@
- }
- TvEntity = class
- public
+ Font: TvFont;
end;
{@@
@@ -145,9 +198,6 @@
{@@
}
-
- { TvEllipse }
-
TvEllipse = class(TvEntity)
public
// Mandatory fields
@@ -159,6 +209,24 @@
procedure CalculateBoundingRectangle;
end;
+ {@@
+ The brush has no effect in this class
+
+ DimensionLeft ---text--- DimensionRight
+ | |
+ | | BaseRight
+ |
+ | BaseLeft
+ }
+
+ { TvAlignedDimension }
+
+ TvAlignedDimension = class(TvEntity)
+ public
+ // Mandatory fields
+ BaseLeft, BaseRight, DimensionLeft, DimensionRight: T3DPoint;
+ end;
+
type
TvCustomVectorialWriter = class;
@@ -168,8 +236,6 @@
TvVectorialDocument = class
private
- FPaths: TFPList;
- FTexts: TFPList;
FEntities: TFPList;
FTmpPath: TPath;
FTmpText: TvText;
@@ -184,10 +250,14 @@
{ Base methods }
constructor Create;
destructor Destroy; override;
- procedure WriteToFile(AFileName: string; AFormat: TvVectorialFormat);
+ 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);
procedure WriteToStrings(AStrings: TStrings; AFormat: TvVectorialFormat);
- procedure ReadFromFile(AFileName: string; AFormat: TvVectorialFormat);
+ procedure ReadFromFile(AFileName: string; AFormat: TvVectorialFormat); overload;
+ procedure ReadFromFile(AFileName: string); overload;
procedure ReadFromStream(AStream: TStream; AFormat: TvVectorialFormat);
procedure ReadFromStrings(AStrings: TStrings; AFormat: TvVectorialFormat);
class function GetFormatFromExtension(AFileName: string): TvVectorialFormat;
@@ -195,27 +265,35 @@
{ 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 StartPath(AX, AY: Double);
+ procedure AddEntity(AEntity: TvEntity);
+ procedure AddPathCopyMem(APath: TPath);
+ procedure StartPath(AX, AY: Double); overload;
+ procedure StartPath(); overload;
+ procedure AddMoveToPath(AX, AY: Double);
procedure AddLineToPath(AX, AY: Double); overload;
+ procedure AddLineToPath(AX, AY: Double; AColor: TFPColor); overload;
procedure AddLineToPath(AX, AY, AZ: Double); overload;
+ procedure GetCurrenPathPenPos(var AX, AY: Double);
procedure AddBezierToPath(AX1, AY1, AX2, AY2, AX3, AY3: Double); overload;
procedure AddBezierToPath(AX1, AY1, AZ1, AX2, AY2, AZ2, AX3, AY3, AZ3: Double); overload;
+ procedure SetBrushColor(AColor: TFPColor);
+ procedure SetBrushStyle(AStyle: TFPBrushStyle);
+ procedure SetPenColor(AColor: TFPColor);
+ procedure SetPenStyle(AStyle: TFPPenStyle);
+ procedure SetPenWidth(AWidth: Integer);
procedure EndPath();
procedure AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string); overload;
procedure AddText(AX, AY, AZ: Double; AStr: utf8string); overload;
procedure AddCircle(ACenterX, ACenterY, ACenterZ, ARadius: Double);
- procedure AddCircularArc(ACenterX, ACenterY, ACenterZ, ARadius, AStartAngle, AEndAngle: Double);
+ procedure AddCircularArc(ACenterX, ACenterY, ACenterZ, ARadius, AStartAngle, AEndAngle: Double; AColor: TFPColor);
procedure AddEllipse(CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle: Double);
+ // Dimensions
+ procedure AddAlignedDimension(BaseLeft, BaseRight, DimLeft, DimRight: T3DPoint);
{ properties }
property PathCount: Integer read GetPathCount;
property Paths[Index: Cardinal]: TPath read GetPath;
@@ -272,6 +350,7 @@
procedure RegisterVectorialWriter(
AWriterClass: TvVectorialWriterClass;
AFormat: TvVectorialFormat);
+function Make2DPoint(AX, AY: Double): T3DPoint;
implementation
@@ -362,6 +441,23 @@
end;
end;
+function Make2DPoint(AX, AY: Double): T3DPoint;
+begin
+ Result.X := AX;
+ Result.Y := AY;
+ Result.Z := 0;
+end;
+
+{ TvEntity }
+
+constructor TvEntity.Create;
+begin
+ Pen.Style := psSolid;
+ Pen.Color := colBlack;
+ Brush.Style := bsClear;
+ Brush.Color := colBlue;
+end;
+
{ TvEllipse }
procedure TvEllipse.CalculateBoundingRectangle;
@@ -415,8 +511,6 @@
begin
inherited Create;
- FPaths := TFPList.Create;
- FTexts := TFPList.Create;
FEntities := TFPList.Create;
FTmpPath := TPath.Create;
end;
@@ -428,40 +522,35 @@
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;
{@@
@@ -487,6 +576,23 @@
FTmpPath.PointsEnd := segment;
end;
+procedure TvVectorialDocument.StartPath();
+begin
+ ClearTmpPath();
+end;
+
+procedure TvVectorialDocument.AddMoveToPath(AX, AY: Double);
+var
+ segment: T2DSegment;
+begin
+ segment := T2DSegment.Create;
+ segment.SegmentType := stMoveTo;
+ segment.X := AX;
+ segment.Y := AY;
+
+ AppendSegmentToTmpPath(segment);
+end;
+
{@@
Adds one more point to the end of a Path being
writing in multiple steps.
@@ -509,6 +615,19 @@
AppendSegmentToTmpPath(segment);
end;
+procedure TvVectorialDocument.AddLineToPath(AX, AY: Double; AColor: TFPColor);
+var
+ segment: T2DSegmentWithPen;
+begin
+ segment := T2DSegmentWithPen.Create;
+ segment.SegmentType := st2DLineWithPen;
+ segment.X := AX;
+ segment.Y := AY;
+ segment.Pen.Color := AColor;
+
+ AppendSegmentToTmpPath(segment);
+end;
+
procedure TvVectorialDocument.AddLineToPath(AX, AY, AZ: Double);
var
segment: T3DSegment;
@@ -523,6 +642,18 @@
end;
{@@
+ Gets the current Pen Pos in the temporary path
+}
+procedure TvVectorialDocument.GetCurrenPathPenPos(var AX, AY: Double);
+begin
+ // Check if we are the first segment in the tmp path
+ if FTmpPath.PointsEnd = nil then raise Exception.Create('[TvVectorialDocument.GetCurrenPathPenPos] One cannot obtain the Pen Pos if there are no segments in the temporary path');
+
+ AX := T2DSegment(FTmpPath.PointsEnd).X;
+ AY := T2DSegment(FTmpPath.PointsEnd).Y;
+end;
+
+{@@
Adds a bezier element to the path. It starts where the previous element ended
and it goes throw the control points [AX1, AY1] and [AX2, AY2] and ends
in [AX3, AY3].
@@ -564,6 +695,31 @@
AppendSegmentToTmpPath(segment);
end;
+procedure TvVectorialDocument.SetBrushColor(AColor: TFPColor);
+begin
+ FTmPPath.Brush.Color := AColor;
+end;
+
+procedure TvVectorialDocument.SetBrushStyle(AStyle: TFPBrushStyle);
+begin
+ FTmPPath.Brush.Style := AStyle;
+end;
+
+procedure TvVectorialDocument.SetPenColor(AColor: TFPColor);
+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
steps using StartPath and AddPointToPath,
@@ -577,7 +733,7 @@
procedure TvVectorialDocument.EndPath();
begin
if FTmPPath.Len = 0 then Exit;
- AddPath(FTmPPath);
+ AddPathCopyMem(FTmPPath);
ClearTmpPath();
end;
@@ -590,9 +746,9 @@
lText.X := AX;
lText.Y := AY;
lText.Z := AZ;
- lText.FontName := FontName;
- lText.FontSize := FontSize;
- FTexts.Add(lText);
+ lText.Font.Name := FontName;
+ lText.Font.Size := FontSize;
+ AddEntity(lText);
end;
procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; AStr: utf8string);
@@ -609,11 +765,11 @@
lCircle.CenterY := ACenterY;
lCircle.CenterZ := ACenterZ;
lCircle.Radius := ARadius;
- FEntities.Add(lCircle);
+ AddEntity(lCircle);
end;
procedure TvVectorialDocument.AddCircularArc(ACenterX, ACenterY, ACenterZ,
- ARadius, AStartAngle, AEndAngle: Double);
+ ARadius, AStartAngle, AEndAngle: Double; AColor: TFPColor);
var
lCircularArc: TvCircularArc;
begin
@@ -624,7 +780,8 @@
lCircularArc.Radius := ARadius;
lCircularArc.StartAngle := AStartAngle;
lCircularArc.EndAngle := AEndAngle;
- FEntities.Add(lCircularArc);
+ lCircularArc.Pen.Color := AColor;
+ AddEntity(lCircularArc);
end;
procedure TvVectorialDocument.AddEllipse(CenterX, CenterY, CenterZ,
@@ -639,7 +796,28 @@
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,
+ DimLeft, DimRight: T3DPoint);
+var
+ lDim: TvAlignedDimension;
+begin
+ lDim := TvAlignedDimension.Create;
+ lDim.BaseLeft := BaseLeft;
+ lDim.BaseRight := BaseRight;
+ lDim.DimensionLeft := DimLeft;
+ lDim.DimensionRight := DimRight;
+ AddEntity(lDim);
end;
{@@
@@ -655,12 +833,13 @@
for i := 0 to Length(GvVectorialFormats) - 1 do
if GvVectorialFormats[i].Format = AFormat then
begin
- Result := GvVectorialFormats[i].WriterClass.Create;
+ if GvVectorialFormats[i].WriterClass <> nil then
+ Result := GvVectorialFormats[i].WriterClass.Create;
Break;
end;
- if Result = nil then raise Exception.Create('Unsuported vector graphics format.');
+ if Result = nil then raise Exception.Create('Unsupported vector graphics format.');
end;
{@@
@@ -676,12 +855,13 @@
for i := 0 to Length(GvVectorialFormats) - 1 do
if GvVectorialFormats[i].Format = AFormat then
begin
- Result := GvVectorialFormats[i].ReaderClass.Create;
+ if GvVectorialFormats[i].ReaderClass <> nil then
+ Result := GvVectorialFormats[i].ReaderClass.Create;
Break;
end;
- if Result = nil then raise Exception.Create('Unsuported vector graphics format.');
+ if Result = nil then raise Exception.Create('Unsupported vector graphics format.');
end;
procedure TvVectorialDocument.ClearTmpPath();
@@ -700,14 +880,28 @@
FTmpPath.Points := nil;
FTmpPath.PointsEnd := nil;
FTmpPath.Len := 0;
+ FTmpPath.Brush.Color := colBlue;
+ FTmpPath.Brush.Style := bsClear;
+ FTmpPath.Pen.Color := colBlack;
+ FTmpPath.Pen.Style := psSolid;
+ FTmpPath.Pen.Width := 1;
end;
procedure TvVectorialDocument.AppendSegmentToTmpPath(ASegment: TPathSegment);
var
L: Integer;
begin
+ // Check if we are the first segment in the tmp path
if FTmpPath.PointsEnd = nil then
- Exception.Create('[TvVectorialDocument.AppendSegmentToTmpPath]' + Str_Error_Nil_Path);
+ begin
+ if FTmpPath.Len <> 0 then
+ Exception.Create('[TvVectorialDocument.AppendSegmentToTmpPath]' + Str_Error_Nil_Path);
+
+ FTmpPath.Points := ASegment;
+ FTmpPath.PointsEnd := ASegment;
+ FTmpPath.Len := 1;
+ Exit;
+ end;
L := FTmpPath.Len;
Inc(FTmpPath.Len);
@@ -736,6 +930,14 @@
end;
end;
+procedure TvVectorialDocument.WriteToFile(AFileName: string);
+var
+ lFormat: TvVectorialFormat;
+begin
+ lFormat := GetFormatFromExtension(ExtractFileExt(AFileName));
+ WriteToFile(AFileName, lFormat);
+end;
+
{@@
Writes the document to a stream
}
@@ -787,6 +989,17 @@
end;
{@@
+ Reads the document from a file. A variant that auto-detects the format from the extension.
+}
+procedure TvVectorialDocument.ReadFromFile(AFileName: string);
+var
+ lFormat: TvVectorialFormat;
+begin
+ lFormat := GetFormatFromExtension(ExtractFileExt(AFileName));
+ ReadFromFile(AFileName, lFormat);
+end;
+
+{@@
Reads the document from a stream.
Any current contents will be removed.
@@ -832,6 +1045,8 @@
else if AnsiCompareText(lExt, STR_SVG_EXTENSION) = 0 then Result := vfSVG
else if AnsiCompareText(lExt, STR_CORELDRAW_EXTENSION) = 0 then Result := vfCorelDrawCDR
else if AnsiCompareText(lExt, STR_WINMETAFILE_EXTENSION) = 0 then Result := vfWindowsMetafileWMF
+ else if AnsiCompareText(lExt, STR_AUTOCAD_EXCHANGE_EXTENSION) = 0 then Result := vfDXF
+ else if AnsiCompareText(lExt, STR_ENCAPSULATEDPOSTSCRIPT_EXTENSION) = 0 then Result := vfEncapsulatedPostScript
else
raise Exception.Create('TvVectorialDocument.GetFormatFromExtension: The extension (' + lExt + ') doesn''t match any supported formats.');
end;
@@ -842,31 +1057,32 @@
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;
-
-function TvVectorialDocument.GetText(ANum: Cardinal): TvText;
-begin
- if ANum >= FTexts.Count then raise Exception.Create('TvVectorialDocument.GetText: Text number out of bounds');
+ Result := 0;
- 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;
@@ -878,7 +1094,7 @@
Result := TvEntity(FEntities.Items[ANum]);
end;
-function TvVectorialDocument.GetEntityCount: Integer;
+function TvVectorialDocument.GetEntitiesCount: Integer;
begin
Result := FEntities.Count;
end;
@@ -888,8 +1104,7 @@
}
procedure TvVectorialDocument.Clear;
begin
- RemoveAllPaths();
- RemoveAllTexts();
+ FEntities.Clear();
end;
{ TvCustomVectorialReader }
@@ -1000,17 +1215,14 @@
{ TPath }
-procedure TPath.Assign(APath: TPath);
+procedure TPath.Assign(ASource: TPath);
begin
- Len := APath.Len;
- Points := APath.Points;
- PointsEnd := APath.PointsEnd;
- CurPoint := APath.CurPoint;
-end;
-
-function TPath.Count(): TPathSegment;
-begin
-
+ Len := ASource.Len;
+ Points := ASource.Points;
+ PointsEnd := ASource.PointsEnd;
+ CurPoint := ASource.CurPoint;
+ Pen := ASource.Pen;
+ Brush := ASource.Brush;
end;
procedure TPath.PrepareForSequentialReading;