diff options
| author | sekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2011-01-30 15:51:36 +0000 |
|---|---|---|
| committer | sekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2011-01-30 15:51:36 +0000 |
| commit | 83982cb1a43013702306f60bd1b98257a7d07e74 (patch) | |
| tree | 1d586105f9fc1bcc9cb8f16f8c4fb0d533e4cf0a /packages/fpvectorial | |
| parent | 6dcd60a1d03b9a30d25169ae8e2780d2becd90aa (diff) | |
| download | fpc-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.pas | 118 | ||||
| -rw-r--r-- | packages/fpvectorial/src/fpvectorial.pas | 3 | ||||
| -rw-r--r-- | packages/fpvectorial/src/fpvtocanvas.pas | 97 |
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} |
