You've already forked lazarus-ccr
Advances the reading support of DXF in fpvviewer
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1462 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -66,15 +66,11 @@ type
|
||||
|
||||
TvDXFVectorialReader = class(TvCustomVectorialReader)
|
||||
private
|
||||
// CIRCLE
|
||||
CircleCenterX, CircleCenterY, CircleCenterZ, CircleRadius: Double;
|
||||
// LINE
|
||||
LineStartX, LineStartY, LineStartZ: Double;
|
||||
LineEndX, LineEndY, LineEndZ: Double;
|
||||
//
|
||||
function SeparateString(AString: string; ASeparator: Char): T10Strings;
|
||||
procedure ReadENTITIES(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
procedure ReadENTITIES_LINE(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
procedure ReadENTITIES_ARC(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
procedure ReadENTITIES_CIRCLE(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
procedure ReadENTITIES_ELLIPSE(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
procedure ReadENTITIES_TEXT(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
@ -318,44 +314,9 @@ begin
|
||||
for i := 0 to ATokens.Count - 1 do
|
||||
begin
|
||||
CurToken := TDXFToken(ATokens.Items[i]);
|
||||
if CurToken.StrValue = 'CIRCLE' then
|
||||
begin
|
||||
CircleCenterX := 0.0;
|
||||
CircleCenterY := 0.0;
|
||||
CircleCenterZ := 0.0;
|
||||
CircleRadius := 0.0;
|
||||
|
||||
ReadENTITIES_CIRCLE(CurToken.Childs, AData);
|
||||
|
||||
AData.AddCircle(CircleCenterX, CircleCenterY,
|
||||
CircleCenterZ, CircleRadius);
|
||||
end
|
||||
else if CurToken.StrValue = 'ELLIPSE' then
|
||||
begin
|
||||
// ...
|
||||
ReadENTITIES_ELLIPSE(CurToken.Childs, AData);
|
||||
end
|
||||
else if CurToken.StrValue = 'LINE' then
|
||||
begin
|
||||
// Initial values
|
||||
LineStartX := 0;
|
||||
LineStartY := 0;
|
||||
LineStartZ := 0;
|
||||
LineEndX := 0;
|
||||
LineEndY := 0;
|
||||
LineEndZ := 0;
|
||||
|
||||
// Read the data of the line
|
||||
ReadENTITIES_LINE(CurToken.Childs, AData);
|
||||
|
||||
// And now write it
|
||||
{$ifdef FPVECTORIALDEBUG}
|
||||
WriteLn(Format('Adding Line from %f,%f to %f,%f', [LineStartX, LineStartY, LineEndX, LineEndY]));
|
||||
{$endif}
|
||||
AData.StartPath(LineStartX, LineStartY);
|
||||
AData.AddLineToPath(LineEndX, LineEndY);
|
||||
AData.EndPath();
|
||||
end
|
||||
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
|
||||
begin
|
||||
// ...
|
||||
@ -367,7 +328,18 @@ procedure TvDXFVectorialReader.ReadENTITIES_LINE(ATokens: TDXFTokens; AData: TvV
|
||||
var
|
||||
CurToken: TDXFToken;
|
||||
i: Integer;
|
||||
// LINE
|
||||
LineStartX, LineStartY, LineStartZ: Double;
|
||||
LineEndX, LineEndY, LineEndZ: Double;
|
||||
begin
|
||||
// Initial values
|
||||
LineStartX := 0;
|
||||
LineStartY := 0;
|
||||
LineStartZ := 0;
|
||||
LineEndX := 0;
|
||||
LineEndY := 0;
|
||||
LineEndZ := 0;
|
||||
|
||||
for i := 0 to ATokens.Count - 1 do
|
||||
begin
|
||||
// Now read and process the item name
|
||||
@ -388,6 +360,62 @@ begin
|
||||
31: LineEndZ := CurToken.FloatValue;
|
||||
end;
|
||||
end;
|
||||
|
||||
// And now write it
|
||||
{$ifdef FPVECTORIALDEBUG}
|
||||
WriteLn(Format('Adding Line from %f,%f to %f,%f', [LineStartX, LineStartY, LineEndX, LineEndY]));
|
||||
{$endif}
|
||||
AData.StartPath(LineStartX, LineStartY);
|
||||
AData.AddLineToPath(LineEndX, LineEndY);
|
||||
AData.EndPath();
|
||||
end;
|
||||
|
||||
{
|
||||
100 Subclass marker (AcDbCircle)
|
||||
39 Thickness (optional; default = 0)
|
||||
10 Center point (in OCS) DXF: X value; APP: 3D point
|
||||
20, 30 DXF: Y and Z values of center point (in OCS)
|
||||
40 Radius
|
||||
100 Subclass marker (AcDbArc)
|
||||
50 Start angle
|
||||
51 End angle
|
||||
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)
|
||||
}
|
||||
procedure TvDXFVectorialReader.ReadENTITIES_ARC(ATokens: TDXFTokens;
|
||||
AData: TvVectorialDocument);
|
||||
var
|
||||
CurToken: TDXFToken;
|
||||
i: Integer;
|
||||
CenterX, CenterY, CenterZ, Radius, StartAngle, EndAngle: Double;
|
||||
begin
|
||||
CenterX := 0.0;
|
||||
CenterY := 0.0;
|
||||
CenterZ := 0.0;
|
||||
Radius := 0.0;
|
||||
StartAngle := 0.0;
|
||||
EndAngle := 0.0;
|
||||
|
||||
for i := 0 to ATokens.Count - 1 do
|
||||
begin
|
||||
// Now read and process the item name
|
||||
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));
|
||||
|
||||
case CurToken.GroupCode of
|
||||
10: CenterX := CurToken.FloatValue;
|
||||
20: CenterY := CurToken.FloatValue;
|
||||
30: CenterZ := CurToken.FloatValue;
|
||||
40: Radius := CurToken.FloatValue;
|
||||
end;
|
||||
end;
|
||||
|
||||
AData.AddCircularArc(CenterX, CenterY, CenterZ, Radius, StartAngle, EndAngle);
|
||||
end;
|
||||
|
||||
{
|
||||
@ -405,7 +433,13 @@ procedure TvDXFVectorialReader.ReadENTITIES_CIRCLE(ATokens: TDXFTokens;
|
||||
var
|
||||
CurToken: TDXFToken;
|
||||
i: Integer;
|
||||
CircleCenterX, CircleCenterY, CircleCenterZ, CircleRadius: Double;
|
||||
begin
|
||||
CircleCenterX := 0.0;
|
||||
CircleCenterY := 0.0;
|
||||
CircleCenterZ := 0.0;
|
||||
CircleRadius := 0.0;
|
||||
|
||||
for i := 0 to ATokens.Count - 1 do
|
||||
begin
|
||||
// Now read and process the item name
|
||||
@ -424,6 +458,9 @@ begin
|
||||
40: CircleRadius := CurToken.FloatValue;
|
||||
end;
|
||||
end;
|
||||
|
||||
AData.AddCircle(CircleCenterX, CircleCenterY,
|
||||
CircleCenterZ, CircleRadius);
|
||||
end;
|
||||
|
||||
{
|
||||
@ -443,7 +480,7 @@ procedure TvDXFVectorialReader.ReadENTITIES_ELLIPSE(ATokens: TDXFTokens;
|
||||
var
|
||||
CurToken: TDXFToken;
|
||||
i: Integer;
|
||||
CenterX, CenterY, CenterZ: Double;
|
||||
CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle: Double;
|
||||
begin
|
||||
for i := 0 to ATokens.Count - 1 do
|
||||
begin
|
||||
@ -461,7 +498,11 @@ begin
|
||||
20: CenterY := CurToken.FloatValue;
|
||||
30: CenterZ := CurToken.FloatValue;
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
//
|
||||
AData.AddEllipse(CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle);
|
||||
end;
|
||||
|
||||
{
|
||||
@ -498,8 +539,35 @@ end;
|
||||
}
|
||||
procedure TvDXFVectorialReader.ReadENTITIES_TEXT(ATokens: TDXFTokens;
|
||||
AData: TvVectorialDocument);
|
||||
var
|
||||
CurToken: TDXFToken;
|
||||
i: Integer;
|
||||
PosX, PosY, PosZ: Double;
|
||||
Str: string;
|
||||
begin
|
||||
for i := 0 to ATokens.Count - 1 do
|
||||
begin
|
||||
// Now read and process the item name
|
||||
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));
|
||||
|
||||
case CurToken.GroupCode of
|
||||
1: Str := CurToken.StrValue;
|
||||
10: PosX := CurToken.FloatValue;
|
||||
20: PosY := CurToken.FloatValue;
|
||||
30: PosZ := CurToken.FloatValue;
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
//
|
||||
// AData.AddEllipse(CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle);
|
||||
end;
|
||||
|
||||
function TvDXFVectorialReader.GetCoordinateValue(AStr: shortstring): Double;
|
||||
|
@ -18,7 +18,7 @@ unit fpvectorial;
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils;
|
||||
Classes, SysUtils, Math;
|
||||
|
||||
type
|
||||
TvVectorialFormat = (
|
||||
@ -121,13 +121,41 @@ type
|
||||
Value: utf8string;
|
||||
end;
|
||||
|
||||
{@@
|
||||
}
|
||||
TvEntity = class
|
||||
public
|
||||
end;
|
||||
|
||||
{@@
|
||||
}
|
||||
TvCircle = class(TvEntity)
|
||||
public
|
||||
X, Y, Z, Radius: Double;
|
||||
CenterX, CenterY, CenterZ, Radius: Double;
|
||||
end;
|
||||
|
||||
{@@
|
||||
}
|
||||
TvCircularArc = class(TvEntity)
|
||||
public
|
||||
CenterX, CenterY, CenterZ, Radius: Double;
|
||||
StartAngle, EndAngle: Double;
|
||||
end;
|
||||
|
||||
{@@
|
||||
}
|
||||
|
||||
{ TvEllipse }
|
||||
|
||||
TvEllipse = class(TvEntity)
|
||||
public
|
||||
// Mandatory fields
|
||||
CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis: Double;
|
||||
{@@ The Angle is measured in radians in relation to the positive X axis }
|
||||
Angle: Double;
|
||||
// Calculated fields
|
||||
BoundingRect: TRect;
|
||||
procedure CalculateBoundingRectangle;
|
||||
end;
|
||||
|
||||
type
|
||||
@ -184,7 +212,9 @@ type
|
||||
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(AX, AY, AZ, ARadius: Double);
|
||||
procedure AddCircle(ACenterX, ACenterY, ACenterZ, ARadius: Double);
|
||||
procedure AddCircularArc(ACenterX, ACenterY, ACenterZ, ARadius, AStartAngle, AEndAngle: Double);
|
||||
procedure AddEllipse(CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle: Double);
|
||||
{ properties }
|
||||
property PathCount: Integer read GetPathCount;
|
||||
property Paths[Index: Cardinal]: TPath read GetPath;
|
||||
@ -331,6 +361,38 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TvEllipse }
|
||||
|
||||
procedure TvEllipse.CalculateBoundingRectangle;
|
||||
var
|
||||
t, tmp: Double;
|
||||
begin
|
||||
{
|
||||
To calculate the bounding rectangle we can do this:
|
||||
|
||||
Ellipse equations:You could try using the parametrized equations for an ellipse rotated at an arbitrary angle:
|
||||
|
||||
x = CenterX + MajorHalfAxis*cos(t)*cos(Angle) - MinorHalfAxis*sin(t)*sin(Angle)
|
||||
y = CenterY + MinorHalfAxis*sin(t)*cos(Angle) + MajorHalfAxis*cos(t)*sin(Angle)
|
||||
|
||||
You can then differentiate and solve for gradient = 0:
|
||||
0 = dx/dt = -MajorHalfAxis*sin(t)*cos(Angle) - MinorHalfAxis*cos(t)*sin(Angle)
|
||||
=>
|
||||
tan(t) = -MinorHalfAxis*tan(Angle)/MajorHalfAxis
|
||||
=>
|
||||
t = cotang(-MinorHalfAxis*tan(Angle)/MajorHalfAxis)
|
||||
|
||||
On the other axis:
|
||||
|
||||
0 = dy/dt = b*cos(t)*cos(phi) - a*sin(t)*sin(phi)
|
||||
=>
|
||||
tan(t) = b*cot(phi)/a
|
||||
}
|
||||
t := cotan(-MinorHalfAxis*tan(Angle)/MajorHalfAxis);
|
||||
tmp := CenterX + MajorHalfAxis*cos(t)*cos(Angle) - MinorHalfAxis*sin(t)*sin(Angle);
|
||||
BoundingRect.Right := Round(tmp);
|
||||
end;
|
||||
|
||||
{ TsWorksheet }
|
||||
|
||||
{@@
|
||||
@ -537,18 +599,48 @@ begin
|
||||
AddText(AX, AY, AZ, '', 10, AStr);
|
||||
end;
|
||||
|
||||
procedure TvVectorialDocument.AddCircle(AX, AY, AZ, ARadius: Double);
|
||||
procedure TvVectorialDocument.AddCircle(ACenterX, ACenterY, ACenterZ, ARadius: Double);
|
||||
var
|
||||
lCircle: TvCircle;
|
||||
begin
|
||||
lCircle := TvCircle.Create;
|
||||
lCircle.X := AX;
|
||||
lCircle.Y := AY;
|
||||
lCircle.Z := AZ;
|
||||
lCircle.CenterX := ACenterX;
|
||||
lCircle.CenterY := ACenterY;
|
||||
lCircle.CenterZ := ACenterZ;
|
||||
lCircle.Radius := ARadius;
|
||||
FEntities.Add(lCircle);
|
||||
end;
|
||||
|
||||
procedure TvVectorialDocument.AddCircularArc(ACenterX, ACenterY, ACenterZ,
|
||||
ARadius, AStartAngle, AEndAngle: Double);
|
||||
var
|
||||
lCircularArc: TvCircularArc;
|
||||
begin
|
||||
lCircularArc := TvCircularArc.Create;
|
||||
lCircularArc.CenterX := ACenterX;
|
||||
lCircularArc.CenterY := ACenterY;
|
||||
lCircularArc.CenterZ := ACenterZ;
|
||||
lCircularArc.Radius := ARadius;
|
||||
lCircularArc.StartAngle := AStartAngle;
|
||||
lCircularArc.EndAngle := AEndAngle;
|
||||
FEntities.Add(lCircularArc);
|
||||
end;
|
||||
|
||||
procedure TvVectorialDocument.AddEllipse(CenterX, CenterY, CenterZ,
|
||||
MajorHalfAxis, MinorHalfAxis, Angle: Double);
|
||||
var
|
||||
lEllipse: TvEllipse;
|
||||
begin
|
||||
lEllipse := TvEllipse.Create;
|
||||
lEllipse.CenterX := CenterX;
|
||||
lEllipse.CenterY := CenterY;
|
||||
lEllipse.CenterZ := CenterZ;
|
||||
lEllipse.MajorHalfAxis := MajorHalfAxis;
|
||||
lEllipse.MinorHalfAxis := MinorHalfAxis;
|
||||
lEllipse.Angle := Angle;
|
||||
FEntities.Add(lEllipse);
|
||||
end;
|
||||
|
||||
{@@
|
||||
Convenience method which creates the correct
|
||||
writer object for a given vector graphics document format.
|
||||
|
@ -14,6 +14,42 @@ procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustom
|
||||
|
||||
implementation
|
||||
|
||||
{function Rotate2DPoint(P,Fix :TPoint; alpha:double): TPoint;
|
||||
var
|
||||
sinus, cosinus : Extended;
|
||||
begin
|
||||
SinCos(alpha, sinus, cosinus);
|
||||
P.x := P.x - Fix.x;
|
||||
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;}
|
||||
|
||||
procedure DrawRotatedEllipse(ADest: TFPCustomCanvas; CurEllipse: TvEllipse);
|
||||
{var
|
||||
PointList: array[0..6] of TPoint;
|
||||
f: TPoint;
|
||||
dk: 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);
|
||||
//Controlpoint of Startpoint first part
|
||||
PointList[2] := Rotate2DPoint(Point(x2- 1, f.y - dk), f, Alpha);
|
||||
//Controlpoint of secondpoint first part
|
||||
PointList[3] := Rotate2DPoint(Point(x2 -1 , f.y), f, Alpha);
|
||||
// Firstpoint of secondpart
|
||||
PointList[4] := Rotate2DPoint(Point(x2-1 , f.y + dk), f, Alpha);
|
||||
// Controllpoint of secondpart firstpoint
|
||||
PointList[5] := Rotate2DPoint(Point(x1, f.y + dk), f, Alpha);
|
||||
// Conrollpoint of secondpart endpoint
|
||||
PointList[6] := PointList[0]; // Endpoint of
|
||||
// Back to the startpoint
|
||||
PolyBezier(canvas.handle, Pointlist[0], 7);}
|
||||
end;
|
||||
|
||||
{@@
|
||||
This function draws a FPVectorial vectorial image to a TFPCustomCanvas
|
||||
descendent, such as TCanvas from the LCL.
|
||||
@ -43,6 +79,8 @@ var
|
||||
// For entities
|
||||
CurEntity: TvEntity;
|
||||
CurCircle: TvCircle;
|
||||
CurEllipse: TvEllipse;
|
||||
CurCircularArc: TvCircularArc;
|
||||
begin
|
||||
{$ifdef FPVECTORIALDEBUG}
|
||||
WriteLn(':>DrawFPVectorialToCanvas');
|
||||
@ -106,15 +144,25 @@ begin
|
||||
for i := 0 to ASource.GetEntityCount - 1 do
|
||||
begin
|
||||
CurEntity := ASource.GetEntity(i);
|
||||
CurCircle := CurEntity as TvCircle;
|
||||
if CurEntity is TvCircle then
|
||||
begin
|
||||
CurCircle := CurEntity as TvCircle;
|
||||
ADest.Ellipse(
|
||||
Round(ADestX + AmulX * (CurCircle.X - CurCircle.Radius)),
|
||||
Round(ADestY + AMulY * (CurCircle.Y - CurCircle.Radius)),
|
||||
Round(ADestX + AmulX * (CurCircle.X + CurCircle.Radius)),
|
||||
Round(ADestY + AMulY * (CurCircle.Y + CurCircle.Radius))
|
||||
Round(ADestX + AmulX * (CurCircle.CenterX - CurCircle.Radius)),
|
||||
Round(ADestY + AMulY * (CurCircle.CenterY - CurCircle.Radius)),
|
||||
Round(ADestX + AmulX * (CurCircle.CenterX + CurCircle.Radius)),
|
||||
Round(ADestY + AMulY * (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
|
||||
CurCircularArc := CurEntity as TvCircularArc;
|
||||
// ADest.Arc(ADest, CurEllipse);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
Reference in New Issue
Block a user