summaryrefslogtreecommitdiff
path: root/packages/fpvectorial
diff options
context:
space:
mode:
authorsekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2>2011-01-30 15:51:36 +0000
committersekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2>2011-01-30 15:51:36 +0000
commit83982cb1a43013702306f60bd1b98257a7d07e74 (patch)
tree1d586105f9fc1bcc9cb8f16f8c4fb0d533e4cf0a /packages/fpvectorial
parent6dcd60a1d03b9a30d25169ae8e2780d2becd90aa (diff)
downloadfpc-83982cb1a43013702306f60bd1b98257a7d07e74.tar.gz
Many reliability improvements to the dxf reader, adds text support for both the dxf reader and the canvas output
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@16850 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'packages/fpvectorial')
-rw-r--r--packages/fpvectorial/src/dxfvectorialreader.pas118
-rw-r--r--packages/fpvectorial/src/fpvectorial.pas3
-rw-r--r--packages/fpvectorial/src/fpvtocanvas.pas97
3 files changed, 166 insertions, 52 deletions
diff --git a/packages/fpvectorial/src/dxfvectorialreader.pas b/packages/fpvectorial/src/dxfvectorialreader.pas
index b9897dd5ba..02f5ab7dac 100644
--- a/packages/fpvectorial/src/dxfvectorialreader.pas
+++ b/packages/fpvectorial/src/dxfvectorialreader.pas
@@ -66,8 +66,13 @@ type
TvDXFVectorialReader = class(TvCustomVectorialReader)
private
+ FPointSeparator: TFormatSettings;
+ // HEADER data
+ ANGBASE: Double;
+ ANGDIR: Integer;
//
function SeparateString(AString: string; ASeparator: Char): T10Strings;
+ procedure ReadHEADER(ATokens: TDXFTokens; AData: TvVectorialDocument);
procedure ReadENTITIES(ATokens: TDXFTokens; AData: TvVectorialDocument);
procedure ReadENTITIES_LINE(ATokens: TDXFTokens; AData: TvVectorialDocument);
procedure ReadENTITIES_ARC(ATokens: TDXFTokens; AData: TvVectorialDocument);
@@ -85,12 +90,24 @@ type
implementation
+{$ifndef Windows}
{$define FPVECTORIALDEBUG}
+{$endif}
const
+ // Items in the HEADER section
+
+ // $ACADVER
+ DXF_AUTOCAD_R10 = 'AC1006'; // 1988
+ DXF_AUTOCAD_R11_and_R12 = 'AC1009'; // 1990
+ DXF_AUTOCAD_R13 = 'AC1012'; // 1994
+ DXF_AUTOCAD_R14 = 'AC1009'; // 1997 http://www.autodesk.com/techpubs/autocad/acadr14/dxf/index.htm
+ DXF_AUTOCAD_2000 = 'AC1500'; // 1999 http://www.autodesk.com/techpubs/autocad/acad2000/dxf/
+
// Group Codes for ENTITIES
DXF_ENTITIES_TYPE = 0;
DXF_ENTITIES_HANDLE = 5;
+ DXF_ENTITIES_LINETYPE_NAME = 6;
DXF_ENTITIES_APPLICATION_GROUP = 102;
DXF_ENTITIES_AcDbEntity = 100;
DXF_ENTITIES_MODEL_OR_PAPER_SPACE = 67; // default=0=model, 1=paper
@@ -306,6 +323,33 @@ begin
end;
end;
+procedure TvDXFVectorialReader.ReadHEADER(ATokens: TDXFTokens;
+ AData: TvVectorialDocument);
+var
+ i: Integer;
+ CurToken: TDXFToken;
+begin
+ i := 0;
+ while i < ATokens.Count do
+ begin
+ CurToken := TDXFToken(ATokens.Items[i]);
+ if CurToken.StrValue = '$ANGBASE' then
+ begin
+ CurToken := TDXFToken(ATokens.Items[i+1]);
+ ANGBASE := StrToFloat(CurToken.StrValue, FPointSeparator);
+ Inc(i);
+ end
+ else if CurToken.StrValue = '$ANGDIR' then
+ begin
+ CurToken := TDXFToken(ATokens.Items[i+1]);
+ ANGDIR := StrToInt(CurToken.StrValue);
+ Inc(i);
+ end;
+
+ Inc(i);
+ end;
+end;
+
procedure TvDXFVectorialReader.ReadENTITIES(ATokens: TDXFTokens; AData: TvVectorialDocument);
var
i: Integer;
@@ -314,7 +358,8 @@ begin
for i := 0 to ATokens.Count - 1 do
begin
CurToken := TDXFToken(ATokens.Items[i]);
- if CurToken.StrValue = 'CIRCLE' then ReadENTITIES_CIRCLE(CurToken.Childs, AData)
+ if CurToken.StrValue = 'ARC' then ReadENTITIES_ARC(CurToken.Childs, AData)
+ else if CurToken.StrValue = 'CIRCLE' then ReadENTITIES_CIRCLE(CurToken.Childs, AData)
else if CurToken.StrValue = 'ELLIPSE' then ReadENTITIES_ELLIPSE(CurToken.Childs, AData)
else if CurToken.StrValue = 'LINE' then ReadENTITIES_LINE(CurToken.Childs, AData)
else if CurToken.StrValue = 'TEXT' then
@@ -346,10 +391,10 @@ begin
CurToken := TDXFToken(ATokens.Items[i]);
// Avoid an exception by previously checking if the conversion can be made
- if (CurToken.GroupCode = DXF_ENTITIES_HANDLE) or
- (CurToken.GroupCode = DXF_ENTITIES_AcDbEntity) then Continue;
-
- CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue));
+ if CurToken.GroupCode in [10, 20, 30, 11, 21, 31] then
+ begin
+ CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
+ end;
case CurToken.GroupCode of
10: LineStartX := CurToken.FloatValue;
@@ -377,8 +422,8 @@ end;
20, 30 DXF: Y and Z values of center point (in OCS)
40 Radius
100 Subclass marker (AcDbArc)
-50 Start angle
-51 End angle
+50 Start angle (degrees)
+51 End angle (degrees)
210 Extrusion direction. (optional; default = 0, 0, 1) DXF: X value; APP: 3D vector
220, 230 DXF: Y and Z values of extrusion direction (optional)
}
@@ -402,16 +447,18 @@ begin
CurToken := TDXFToken(ATokens.Items[i]);
// Avoid an exception by previously checking if the conversion can be made
- if (CurToken.GroupCode = DXF_ENTITIES_HANDLE) or
- (CurToken.GroupCode = DXF_ENTITIES_AcDbEntity) then Continue;
-
- CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue));
+ if CurToken.GroupCode in [10, 20, 30, 40, 50, 51] then
+ begin
+ CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
+ end;
case CurToken.GroupCode of
10: CenterX := CurToken.FloatValue;
20: CenterY := CurToken.FloatValue;
30: CenterZ := CurToken.FloatValue;
40: Radius := CurToken.FloatValue;
+ 50: StartAngle := CurToken.FloatValue;
+ 51: EndAngle := CurToken.FloatValue;
end;
end;
@@ -446,10 +493,10 @@ begin
CurToken := TDXFToken(ATokens.Items[i]);
// Avoid an exception by previously checking if the conversion can be made
- if (CurToken.GroupCode = DXF_ENTITIES_HANDLE) or
- (CurToken.GroupCode = DXF_ENTITIES_AcDbEntity) then Continue;
-
- CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue));
+ if CurToken.GroupCode in [10, 20, 30, 40] then
+ begin
+ CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
+ end;
case CurToken.GroupCode of
10: CircleCenterX := CurToken.FloatValue;
@@ -488,17 +535,16 @@ begin
CurToken := TDXFToken(ATokens.Items[i]);
// Avoid an exception by previously checking if the conversion can be made
- if (CurToken.GroupCode = DXF_ENTITIES_HANDLE) or
- (CurToken.GroupCode = DXF_ENTITIES_AcDbEntity) then Continue;
-
- CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue));
+ if CurToken.GroupCode in [10, 20, 30] then
+ begin
+ CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
+ end;
case CurToken.GroupCode of
10: CenterX := CurToken.FloatValue;
20: CenterY := CurToken.FloatValue;
30: CenterZ := CurToken.FloatValue;
end;
-
end;
//
@@ -542,8 +588,11 @@ procedure TvDXFVectorialReader.ReadENTITIES_TEXT(ATokens: TDXFTokens;
var
CurToken: TDXFToken;
i: Integer;
- PosX, PosY, PosZ: Double;
- Str: string;
+ PosX: Double = 0.0;
+ PosY: Double = 0.0;
+ PosZ: Double = 0.0;
+ FontSize: Double = 10.0;
+ Str: string = '';
begin
for i := 0 to ATokens.Count - 1 do
begin
@@ -551,23 +600,22 @@ begin
CurToken := TDXFToken(ATokens.Items[i]);
// Avoid an exception by previously checking if the conversion can be made
- if (CurToken.GroupCode = DXF_ENTITIES_HANDLE) or
- (CurToken.GroupCode = 1) or
- (CurToken.GroupCode = DXF_ENTITIES_AcDbEntity) then Continue;
-
- CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue));
+ if CurToken.GroupCode in [10, 20, 30, 40] then
+ begin
+ CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
+ end;
case CurToken.GroupCode of
1: Str := CurToken.StrValue;
10: PosX := CurToken.FloatValue;
20: PosY := CurToken.FloatValue;
30: PosZ := CurToken.FloatValue;
+ 40: FontSize := CurToken.FloatValue;
end;
-
end;
//
-// AData.AddEllipse(CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle);
+ AData.AddText(PosX, PosY, PosZ, '', Round(FontSize), Str);
end;
function TvDXFVectorialReader.GetCoordinateValue(AStr: shortstring): Double;
@@ -583,6 +631,14 @@ constructor TvDXFVectorialReader.Create;
begin
inherited Create;
+ FPointSeparator := DefaultFormatSettings;
+ FPointSeparator.DecimalSeparator := '.';
+ FPointSeparator.ThousandSeparator := '#';// disable the thousand separator
+
+ // Default HEADER data
+ ANGBASE := 0.0; // Starts pointing to the right / east
+ ANGDIR := 0; // counter-clock wise
+
Tokenizer := TDXFTokenizer.Create;
end;
@@ -610,7 +666,9 @@ begin
CurToken := TDXFToken(Tokenizer.Tokens.Items[i]);
CurTokenFirstChild := TDXFToken(CurToken.Childs.Items[0]);
- if CurTokenFirstChild.StrValue = 'ENTITIES' then
+ if CurTokenFirstChild.StrValue = 'HEADER' then
+ ReadHEADER(CurToken.Childs, AData)
+ else if CurTokenFirstChild.StrValue = 'ENTITIES' then
ReadENTITIES(CurToken.Childs, AData);
end;
end;
diff --git a/packages/fpvectorial/src/fpvectorial.pas b/packages/fpvectorial/src/fpvectorial.pas
index 6c51191847..af0feaa868 100644
--- a/packages/fpvectorial/src/fpvectorial.pas
+++ b/packages/fpvectorial/src/fpvectorial.pas
@@ -139,6 +139,7 @@ type
TvCircularArc = class(TvEntity)
public
CenterX, CenterY, CenterZ, Radius: Double;
+ {@@ The Angle is measured in degrees in relation to the positive X axis }
StartAngle, EndAngle: Double;
end;
@@ -151,7 +152,7 @@ type
public
// Mandatory fields
CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis: Double;
- {@@ The Angle is measured in radians in relation to the positive X axis }
+ {@@ The Angle is measured in degrees in relation to the positive X axis }
Angle: Double;
// Calculated fields
BoundingRect: TRect;
diff --git a/packages/fpvectorial/src/fpvtocanvas.pas b/packages/fpvectorial/src/fpvtocanvas.pas
index f80ab900e0..6893c3b115 100644
--- a/packages/fpvectorial/src/fpvtocanvas.pas
+++ b/packages/fpvectorial/src/fpvtocanvas.pas
@@ -4,17 +4,28 @@ unit fpvtocanvas;
interface
+{.$define USE_LCL_CANVAS}
+
uses
- Classes, SysUtils,
+ Classes, SysUtils, Math,
+ {$ifdef USE_LCL_CANVAS}
+ Graphics, LCLIntf,
+ {$else}
fpcanvas,
+ {$endif}
fpvectorial;
-procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustomCanvas;
+procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
+ {$ifdef USE_LCL_CANVAS}
+ ADest: TCanvas;
+ {$else}
+ ADest: TFPCustomCanvas;
+ {$endif}
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
implementation
-{function Rotate2DPoint(P,Fix :TPoint; alpha:double): TPoint;
+function Rotate2DPoint(P,Fix :TPoint; alpha:double): TPoint;
var
sinus, cosinus : Extended;
begin
@@ -23,31 +34,46 @@ begin
P.y := P.y - Fix.y;
result.x := Round(p.x*cosinus + p.y*sinus) + fix.x ;
result.y := Round(-p.x*sinus + p.y*cosinus) + Fix.y;
-end;}
+end;
-procedure DrawRotatedEllipse(ADest: TFPCustomCanvas; CurEllipse: TvEllipse);
-{var
+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: Integer;}
+ dk, x1, x2, y1, y2: Integer;
begin
-{ dk := Round(0.654 * Abs(y2-y1));
- f.x := CurEllipse.CenterX;
- f.y := CurEllipse.CenterY - 1;
- PointList[0] := Rotate2DPoint(Point(x1, f.y), f, Alpha) ; // Startpoint
- PointList[1] := Rotate2DPoint(Point(x1, f.y - dk), f, Alpha);
+ {$ifdef USE_LCL_CANVAS}
+ CurEllipse.CalculateBoundingRectangle();
+ x1 := CurEllipse.BoundingRect.Left;
+ x2 := CurEllipse.BoundingRect.Right;
+ y1 := CurEllipse.BoundingRect.Top;
+ y2 := CurEllipse.BoundingRect.Bottom;
+
+ dk := Round(0.654 * Abs(y2-y1));
+ f.x := Round(CurEllipse.CenterX);
+ f.y := Round(CurEllipse.CenterY - 1);
+ PointList[0] := Rotate2DPoint(Point(x1, f.y), f, CurEllipse.Angle) ; // Startpoint
+ PointList[1] := Rotate2DPoint(Point(x1, f.y - dk), f, CurEllipse.Angle);
//Controlpoint of Startpoint first part
- PointList[2] := Rotate2DPoint(Point(x2- 1, f.y - dk), f, Alpha);
+ PointList[2] := Rotate2DPoint(Point(x2- 1, f.y - dk), f, CurEllipse.Angle);
//Controlpoint of secondpoint first part
- PointList[3] := Rotate2DPoint(Point(x2 -1 , f.y), f, Alpha);
+ PointList[3] := Rotate2DPoint(Point(x2 -1 , f.y), f, CurEllipse.Angle);
// Firstpoint of secondpart
- PointList[4] := Rotate2DPoint(Point(x2-1 , f.y + dk), f, Alpha);
+ PointList[4] := Rotate2DPoint(Point(x2-1 , f.y + dk), f, CurEllipse.Angle);
// Controllpoint of secondpart firstpoint
- PointList[5] := Rotate2DPoint(Point(x1, f.y + dk), f, Alpha);
+ PointList[5] := Rotate2DPoint(Point(x1, f.y + dk), f, CurEllipse.Angle);
// Conrollpoint of secondpart endpoint
PointList[6] := PointList[0]; // Endpoint of
// Back to the startpoint
- PolyBezier(canvas.handle, Pointlist[0], 7);}
+ ADest.PolyBezier(Pointlist[0]);
+ {$endif}
end;
{@@
@@ -64,7 +90,12 @@ end;
DrawFPVectorialToCanvas(ASource, ADest, 0, ASource.Height, 1.0, -1.0);
}
-procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustomCanvas;
+procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
+ {$ifdef USE_LCL_CANVAS}
+ ADest: TCanvas;
+ {$else}
+ ADest: TFPCustomCanvas;
+ {$endif}
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
var
i, j, k: Integer;
@@ -76,11 +107,13 @@ var
CurX, CurY: Integer; // Not modified by ADestX, etc
CurveLength: Integer;
t: Double;
+ // For text
+ CurText: TvText;
// For entities
CurEntity: TvEntity;
CurCircle: TvCircle;
CurEllipse: TvEllipse;
- CurCircularArc: TvCircularArc;
+ CurArc: TvCircularArc;
begin
{$ifdef FPVECTORIALDEBUG}
WriteLn(':>DrawFPVectorialToCanvas');
@@ -91,6 +124,7 @@ begin
ADest.MoveTo(ADestX, ADestY);
+ // Draws all paths
for i := 0 to ASource.PathCount - 1 do
begin
//WriteLn('i = ', i);
@@ -141,6 +175,7 @@ begin
end;
end;
+ // Draws all entities
for i := 0 to ASource.GetEntityCount - 1 do
begin
CurEntity := ASource.GetEntity(i);
@@ -161,11 +196,31 @@ begin
end
else if CurEntity is TvCircularArc then
begin
- CurCircularArc := CurEntity as TvCircularArc;
-// ADest.Arc(ADest, CurEllipse);
+ CurArc := CurEntity as TvCircularArc;
+ {$ifdef USE_LCL_CANVAS}
+ // Arc(ALeft, ATop, ARight, ABottom, Angle16Deg, Angle16DegLength: Integer);
+ ADest.Arc(
+ Round(ADestX + AmulX * (CurArc.CenterX - CurArc.Radius)),
+ Round(ADestY + AmulY * (CurArc.CenterY - CurArc.Radius)),
+ Round(ADestX + AmulX * (CurArc.CenterX + CurArc.Radius)),
+ Round(ADestY + AmulY * (CurArc.CenterY + CurArc.Radius)),
+ Round(16*CurArc.StartAngle),
+ Round(16*CurArc.EndAngle - CurArc.StartAngle)
+ );
+ {$endif}
end;
end;
+ // Draws all text
+ for i := 0 to ASource.GetTextCount - 1 do
+ begin
+ CurText := ASource.GetText(i);
+ ADest.Font.Height := Round(AmulY * CurText.FontSize);
+ ADest.Pen.Style := psSolid;
+ ADest.Pen.Color := clBlack;
+ ADest.TextOut(Round(CurText.X), Round(CurText.Y), CurText.Value);
+ end;
+
{$ifdef FPVECTORIALDEBUG}
WriteLn(':<DrawFPVectorialToCanvas');
{$endif}