summaryrefslogtreecommitdiff
path: root/packages/fpvectorial
diff options
context:
space:
mode:
authorsekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2>2011-03-08 14:28:26 +0000
committersekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2>2011-03-08 14:28:26 +0000
commitd6c6b6a9aee8f86fd37ba32492ac0ed692c83096 (patch)
tree7c8ce5f714c92ab7190ccdecef84ab294b9ad16f /packages/fpvectorial
parent2a5f2dc122ce7eff5ffcb94a469c8394d28cbc4d (diff)
downloadfpc-d6c6b6a9aee8f86fd37ba32492ac0ed692c83096.tar.gz
Fixes compiling avisocncvectorialwriter, adds a dimension entity and multiple improvements to fpvtocanvas and the DXF vectorial reader
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@17092 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'packages/fpvectorial')
-rw-r--r--packages/fpvectorial/src/avisocncgcodewriter.pas44
-rw-r--r--packages/fpvectorial/src/dxfvectorialreader.pas270
-rw-r--r--packages/fpvectorial/src/fpvectorial.pas32
-rw-r--r--packages/fpvectorial/src/fpvtocanvas.pas209
4 files changed, 513 insertions, 42 deletions
diff --git a/packages/fpvectorial/src/avisocncgcodewriter.pas b/packages/fpvectorial/src/avisocncgcodewriter.pas
index cc31e608a1..eddb18cad9 100644
--- a/packages/fpvectorial/src/avisocncgcodewriter.pas
+++ b/packages/fpvectorial/src/avisocncgcodewriter.pas
@@ -36,6 +36,10 @@ var
i, j: Integer;
Str: string;
APath: TPath;
+ CurSegment: T2DSegment;
+ Cur3DSegment: T3DSegment;
+ Cur2DBezierSegment: T2DBezierSegment;
+ Cur3DBezierSegment: T3DBezierSegment;
begin
AStrings.Clear;
@@ -51,25 +55,39 @@ begin
// levanta a broca
AStrings.Add('P01 // Sobe a cabeça de gravação');
// vai para o ponto inicial
+ CurSegment := T2DSegment(APath.Points);
AStrings.Add(Format('G01 X%f Y%f',
- [APath.Points[0].X, APath.Points[0].Y]));
+ [CurSegment.X, CurSegment.Y]));
AStrings.Add('P02 // Abaixa a cabeça de gravação');
for j := 1 to APath.Len - 1 do
begin
- case APath.Points[j].SegmentType of
+ CurSegment := T2DSegment(CurSegment.Next);
+ case CurSegment.SegmentType of
st2DLine: AStrings.Add(Format('G01 X%f Y%f',
- [APath.Points[j].X, APath.Points[j].Y]));
- st3DLine: AStrings.Add(Format('G01 X%f Y%f Z%f',
- [APath.Points[j].X, APath.Points[j].Y, APath.Points[j].Z]));
- st2DBezier: AStrings.Add(Format('B02 X%f Y%f X%f Y%f X%f Y%f',
- [APath.Points[j].X2, APath.Points[j].Y2,
- APath.Points[j].X3, APath.Points[j].Y3,
- APath.Points[j].X, APath.Points[j].Y]));
- st3DBezier: AStrings.Add(Format('B03 X%f Y%f Z%f X%f Y%f Z%f X%f Y%f Z%f',
- [APath.Points[j].X2, APath.Points[j].Y2, APath.Points[j].Z2,
- APath.Points[j].X3, APath.Points[j].Y3, APath.Points[j].Z3,
- APath.Points[j].X, APath.Points[j].Y, APath.Points[j].Z]));
+ [CurSegment.X, CurSegment.Y]));
+ st3DLine:
+ begin
+ Cur3DSegment := T3DSegment(CurSegment);
+ AStrings.Add(Format('G01 X%f Y%f Z%f',
+ [Cur3DSegment.X, Cur3DSegment.Y, Cur3DSegment.Z]));
+ end;
+ st2DBezier:
+ begin
+ Cur2DBezierSegment := T2DBezierSegment(CurSegment);
+ AStrings.Add(Format('B02 X%f Y%f X%f Y%f X%f Y%f',
+ [Cur2DBezierSegment.X2, Cur2DBezierSegment.Y2,
+ Cur2DBezierSegment.X3, Cur2DBezierSegment.Y3,
+ Cur2DBezierSegment.X, Cur2DBezierSegment.Y]));
+ end;
+ st3DBezier:
+ begin
+ Cur3DBezierSegment := T3DBezierSegment(CurSegment);
+ AStrings.Add(Format('B03 X%f Y%f Z%f X%f Y%f Z%f X%f Y%f Z%f',
+ [Cur3DBezierSegment.X2, Cur3DBezierSegment.Y2, Cur3DBezierSegment.Z2,
+ Cur3DBezierSegment.X3, Cur3DBezierSegment.Y3, Cur3DBezierSegment.Z3,
+ Cur3DBezierSegment.X, Cur3DBezierSegment.Y, Cur3DBezierSegment.Z]));
+ end;
end;
end;
end;
diff --git a/packages/fpvectorial/src/dxfvectorialreader.pas b/packages/fpvectorial/src/dxfvectorialreader.pas
index 02f5ab7dac..f185084947 100644
--- a/packages/fpvectorial/src/dxfvectorialreader.pas
+++ b/packages/fpvectorial/src/dxfvectorialreader.pas
@@ -29,11 +29,10 @@ unit dxfvectorialreader;
interface
uses
- Classes, SysUtils,
+ Classes, SysUtils, Math,
fpvectorial;
type
-
{ Used by tcutils.SeparateString }
T10Strings = array[0..9] of shortstring;
@@ -70,6 +69,9 @@ type
// HEADER data
ANGBASE: Double;
ANGDIR: Integer;
+ INSBASE, EXTMIN, EXTMAX, LIMMIN, LIMMAX: T3DPoint;
+ // Calculated HEADER data
+ DOC_OFFSET: T3DPoint;
//
function SeparateString(AString: string; ASeparator: Char): T10Strings;
procedure ReadHEADER(ATokens: TDXFTokens; AData: TvVectorialDocument);
@@ -77,6 +79,7 @@ type
procedure ReadENTITIES_LINE(ATokens: TDXFTokens; AData: TvVectorialDocument);
procedure ReadENTITIES_ARC(ATokens: TDXFTokens; AData: TvVectorialDocument);
procedure ReadENTITIES_CIRCLE(ATokens: TDXFTokens; AData: TvVectorialDocument);
+ procedure ReadENTITIES_DIMENSION(ATokens: TDXFTokens; AData: TvVectorialDocument);
procedure ReadENTITIES_ELLIPSE(ATokens: TDXFTokens; AData: TvVectorialDocument);
procedure ReadENTITIES_TEXT(ATokens: TDXFTokens; AData: TvVectorialDocument);
function GetCoordinateValue(AStr: shortstring): Double;
@@ -326,8 +329,9 @@ end;
procedure TvDXFVectorialReader.ReadHEADER(ATokens: TDXFTokens;
AData: TvVectorialDocument);
var
- i: Integer;
+ i, j: Integer;
CurToken: TDXFToken;
+ CurField: P3DPoint;
begin
i := 0;
while i < ATokens.Count do
@@ -344,10 +348,71 @@ begin
CurToken := TDXFToken(ATokens.Items[i+1]);
ANGDIR := StrToInt(CurToken.StrValue);
Inc(i);
+ end
+ // This indicates the size of the document
+ else if (CurToken.StrValue = '$INSBASE') or
+ (CurToken.StrValue = '$EXTMIN') or (CurToken.StrValue = '$EXTMAX') or
+ (CurToken.StrValue = '$LIMMIN') or (CurToken.StrValue = '$LIMMAX') then
+ begin
+ if (CurToken.StrValue = '$INSBASE') then CurField := @INSBASE
+ else if (CurToken.StrValue = '$EXTMIN') then CurField := @EXTMIN
+ else if (CurToken.StrValue = '$EXTMAX') then CurField := @EXTMAX
+ else if (CurToken.StrValue = '$LIMMIN') then CurField := @LIMMIN
+ else if (CurToken.StrValue = '$LIMMAX') then CurField := @LIMMAX;
+
+ // Check the next 2 items and verify if they are the values of the size of the document
+ for j := 0 to 1 do
+ begin
+ CurToken := TDXFToken(ATokens.Items[i+1]);
+ case CurToken.GroupCode of
+ 10:
+ begin;
+ CurField^.X := StrToFloat(CurToken.StrValue, FPointSeparator);
+ Inc(i);
+ end;
+ 20:
+ begin
+ CurField^.Y := StrToFloat(CurToken.StrValue, FPointSeparator);
+ Inc(i);
+ end;
+ end;
+ end;
end;
Inc(i);
end;
+
+ // After getting all the data, we can try to make some sense out of it
+
+ // Sometimes EXTMIN comes as 10^20 and EXTMAX as -10^20, which makes no sence
+ // In these cases we need to ignore them.
+ if (EXTMIN.X > 10000000000) or (EXTMIN.X < -10000000000)
+ or (EXTMAX.X > 10000000000) or (EXTMAX.X < -10000000000) then
+ begin
+ DOC_OFFSET.X := 0;
+ DOC_OFFSET.Y := 0;
+
+ AData.Width := LIMMAX.X;
+ AData.Height := LIMMAX.Y;
+ end
+ else
+ begin
+ // The size of the document seams to be given by:
+ // DOC_SIZE = min(EXTMAX, LIMMAX) - DOC_OFFSET;
+ // if EXTMIN is <> -infinite then DOC_OFFSET = EXTMIN else DOC_OFFSET = (0, 0)
+ // We will shift the whole document so that it has only positive coordinates and
+ // DOC_OFFSET will be utilized for that
+
+ if EXTMIN.X > -100 then
+ begin
+ DOC_OFFSET.X := EXTMIN.X;
+ DOC_OFFSET.Y := EXTMIN.Y;
+ end
+ else FillChar(DOC_OFFSET, sizeof(T3DPoint), #0);
+
+ AData.Width := min(EXTMAX.X, LIMMAX.X) - DOC_OFFSET.X;
+ AData.Height := min(EXTMAX.Y, LIMMAX.Y) - DOC_OFFSET.Y;
+ end;
end;
procedure TvDXFVectorialReader.ReadENTITIES(ATokens: TDXFTokens; AData: TvVectorialDocument);
@@ -360,9 +425,11 @@ begin
CurToken := TDXFToken(ATokens.Items[i]);
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 = 'DIMENSION' then ReadENTITIES_DIMENSION(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
+ else if CurToken.StrValue = 'TEXT' then ReadENTITIES_TEXT(CurToken.Childs, AData)
+ else
begin
// ...
end;
@@ -406,9 +473,15 @@ begin
end;
end;
+ // Position fixing for documents with negative coordinates
+ LineStartX := LineStartX - DOC_OFFSET.X;
+ LineStartY := LineStartY - DOC_OFFSET.Y;
+ LineEndX := LineEndX - DOC_OFFSET.X;
+ LineEndY := LineEndY - DOC_OFFSET.Y;
+
// And now write it
{$ifdef FPVECTORIALDEBUG}
- WriteLn(Format('Adding Line from %f,%f to %f,%f', [LineStartX, LineStartY, LineEndX, LineEndY]));
+ // WriteLn(Format('Adding Line from %f,%f to %f,%f', [LineStartX, LineStartY, LineEndX, LineEndY]));
{$endif}
AData.StartPath(LineStartX, LineStartY);
AData.AddLineToPath(LineEndX, LineEndY);
@@ -416,6 +489,8 @@ begin
end;
{
+Arcs are always counter-clockwise in DXF
+
100 Subclass marker (AcDbCircle)
39 Thickness (optional; default = 0)
10 Center point (in OCS) DXF: X value; APP: 3D point
@@ -462,6 +537,18 @@ begin
end;
end;
+ // In DXF the EndAngle is always greater then the StartAngle.
+ // If it isn't then sum 360 to it to make sure we don't get wrong results
+ if EndAngle < StartAngle then EndAngle := EndAngle + 360;
+
+ // Position fixing for documents with negative coordinates
+ CenterX := CenterX - DOC_OFFSET.X;
+ CenterY := CenterY - DOC_OFFSET.Y;
+
+ {$ifdef FPVECTORIALDEBUG}
+ WriteLn(Format('Adding Arc Center=%f,%f Radius=%f StartAngle=%f EndAngle=%f',
+ [CenterX, CenterY, Radius, StartAngle, EndAngle]));
+ {$endif}
AData.AddCircularArc(CenterX, CenterY, CenterZ, Radius, StartAngle, EndAngle);
end;
@@ -506,11 +593,176 @@ begin
end;
end;
+ // Position fixing for documents with negative coordinates
+ CircleCenterX := CircleCenterX - DOC_OFFSET.X;
+ CircleCenterY := CircleCenterY - DOC_OFFSET.Y;
+
AData.AddCircle(CircleCenterX, CircleCenterY,
CircleCenterZ, CircleRadius);
end;
{
+Group codes Description
+100 Subclass marker (AcDbDimension)
+2 Name of the block that contains the entities that make up the dimension picture
+10 Definition point (in WCS) DXF: X value; APP: 3D point
+20, 30 DXF: Y and Z values of definition point (in WCS)
+11 Middle point of dimension text (in OCS) DXF: X value; APP: 3D point
+21, 31 DXF: Y and Z values of middle point of dimension text (in OCS)
+70 Dimension type.
+ Values 0-6 are integer values that represent the dimension type.
+ Values 32, 64, and 128 are bit values, which are added to the integer values
+ (value 32 is always set in R13 and later releases).
+ 0 = Rotated, horizontal, or vertical; 1 = Aligned;
+ 2 = Angular; 3 = Diameter; 4 = Radius;
+ 5 = Angular 3 point; 6 = Ordinate;
+ 32 = Indicates that the block reference (group code 2) is referenced by this dimension only.
+ 64 = Ordinate type. This is a bit value (bit 7) used only with integer value 6.
+ If set, ordinate is X-type; if not set, ordinate is Y-type.
+ 128 = This is a bit value (bit 8) added to the other group 70 values
+ if the dimension text has been positioned at a user-defined location
+ rather than at the default location.
+71 Attachment point:
+ 1 = Top left; 2 = Top center; 3 = Top right;
+ 4 = Middle left; 5 = Middle center; 6 = Middle right;
+ 7 = Bottom left; 8 = Bottom center; 9 = Bottom right
+72 Dimension text line spacing style (optional):
+ 1(or missing) = At least (taller characters will override)
+ 2 = Exact (taller characters will not override)
+41 Dimension text line spacing factor (optional):
+ Percentage of default (3-on-5) line spacing to be applied. Valid values range from 0.25 to 4.00.
+42 Actual measurement (optional; read-only value)
+1 Dimension text explicitly entered by the user. Optional; default is the measurement.
+ If null or "<>", the dimension measurement is drawn as the text,
+ if " " (one blank space), the text is suppressed. Anything else is drawn as the text.
+53 The optional group code 53 is the rotation angle of the dimension
+ text away from its default orientation (the direction of the dimension line) (optional).
+51 All dimension types have an optional 51 group code, which indicates the
+ horizontal direction for the dimension entity. The dimension entity determines
+ the orientation of dimension text and lines for horizontal, vertical, and
+ rotated linear dimensions.
+ This group value is the negative of the angle between the OCS X axis
+ and the UCS X axis. It is always in the XY plane of the OCS.
+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)
+3 Dimension style name
+
+Aligned Dimension Group Codes
+
+100 Subclass marker (AcDbAlignedDimension)
+12 Insertion point for clones of a dimension-Baseline and Continue (in OCS) DXF: X value; APP: 3D point
+22, 32 DXF: Y and Z values of insertion point for clones of a dimension-Baseline and Continue (in OCS)
+13 Definition point for linear and angular dimensions (in WCS) DXF: X value; APP: 3D point
+23, 33 DXF: Y and Z values of definition point for linear and angular dimensions (in WCS)
+14 Definition point for linear and angular dimensions (in WCS) DXF: X value; APP: 3D point
+24, 34 DXF: Y and Z values of definition point for linear and angular dimensions (in WCS)
+
+ |--text--|->10,20
+ | |
+ | |
+ X->14,24 X->13,23
+}
+procedure TvDXFVectorialReader.ReadENTITIES_DIMENSION(ATokens: TDXFTokens;
+ AData: TvVectorialDocument);
+var
+ CurToken: TDXFToken;
+ i: Integer;
+ // DIMENSION
+ BaseLeft, BaseRight, DimensionRight, DimensionLeft, TmpPoint: T3DPoint;
+ IsAlignedDimension: Boolean = False;
+begin
+ // Initial values
+ BaseLeft.X := 0;
+ BaseLeft.Y := 0;
+ BaseRight.X := 0;
+ BaseRight.X := 0;
+ DimensionRight.X := 0;
+ DimensionRight.Y := 0;
+ DimensionLeft.X := 0;
+ DimensionLeft.Y := 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 in [10, 20, 30, 11, 21, 31, 13, 23, 33, 14, 24, 34] then
+ begin
+ CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
+ end;
+
+ case CurToken.GroupCode of
+ 10: DimensionRight.X := CurToken.FloatValue;
+ 20: DimensionRight.Y := CurToken.FloatValue;
+ 30: DimensionRight.Z := CurToken.FloatValue;
+ 13: BaseRight.X := CurToken.FloatValue;
+ 23: BaseRight.Y := CurToken.FloatValue;
+ 33: BaseRight.Z := CurToken.FloatValue;
+ 14: BaseLeft.X := CurToken.FloatValue;
+ 24: BaseLeft.Y := CurToken.FloatValue;
+ 34: BaseLeft.Z := CurToken.FloatValue;
+ 100:
+ begin
+ if CurToken.StrValue = 'AcDbAlignedDimension' then IsAlignedDimension := True;
+ end;
+ end;
+ end;
+
+ // And now write it
+ {$ifdef FPVECTORIALDEBUG}
+// WriteLn(Format('Adding Line from %f,%f to %f,%f', [LineStartX, LineStartY, LineEndX, LineEndY]));
+ {$endif}
+ if IsAlignedDimension then
+ begin
+ // Now make sure that we actually that BaseLeft is to the left of BaseRight
+ if BaseRight.X < BaseLeft.X then
+ begin
+ TmpPoint := BaseRight;
+ BaseRight := BaseLeft;
+ BaseLeft := TmpPoint;
+ end;
+
+ // Now check if we are a horizontal or vertical dimension
+
+ // horizontal
+ //
+ //DL____ DR
+ // | |
+ // | |
+ // BL BR
+ if DimensionRight.X = BaseRight.X then
+ begin
+ DimensionLeft.X := BaseLeft.X;
+ DimensionLeft.Y := DimensionRight.Y;
+ end
+ // vertical
+ //
+ // BL ----|DR
+ // BR --|DL
+ //
+ // In this case we invert then DR and DL
+ else if DimensionRight.Y = BaseLeft.Y then
+ begin
+ DimensionLeft := DimensionRight;
+ DimensionRight.Y := BaseRight.Y;
+ end
+ // vertical
+ //
+ // BL ----|DL
+ // BR --|DR
+ //
+ else if DimensionRight.Y = BaseRight.Y then
+ begin
+ DimensionLeft.X := DimensionRight.X;
+ DimensionLeft.Y := BaseLeft.Y;
+ end;
+
+ AData.AddAlignedDimension(BaseLeft, BaseRight, DimensionLeft, DimensionRight);
+ end;
+end;
+
+{
100 Subclass marker (AcDbEllipse)
10 Center point (in WCS) DXF: X value; APP: 3D point
20, 30 DXF: Y and Z values of center point (in WCS)
@@ -547,6 +799,10 @@ begin
end;
end;
+ // Position fixing for documents with negative coordinates
+ CenterX := CenterX - DOC_OFFSET.X;
+ CenterY := CenterY - DOC_OFFSET.Y;
+
//
AData.AddEllipse(CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle);
end;
@@ -614,6 +870,10 @@ begin
end;
end;
+ // Position fixing for documents with negative coordinates
+ PosX := PosX - DOC_OFFSET.X;
+ PosY := PosY - DOC_OFFSET.Y;
+
//
AData.AddText(PosX, PosY, PosZ, '', Round(FontSize), Str);
end;
diff --git a/packages/fpvectorial/src/fpvectorial.pas b/packages/fpvectorial/src/fpvectorial.pas
index af0feaa868..928b001d11 100644
--- a/packages/fpvectorial/src/fpvectorial.pas
+++ b/packages/fpvectorial/src/fpvectorial.pas
@@ -39,6 +39,12 @@ const
STR_WINMETAFILE_EXTENSION = '.wmf';
type
+ T3DPoint = record
+ X, Y, Z: Double;
+ end;
+
+ P3DPoint = ^T3DPoint;
+
TSegmentType = (
st2DLine, st2DBezier,
st3DLine, st3DBezier, stMoveTo);
@@ -159,6 +165,17 @@ type
procedure CalculateBoundingRectangle;
end;
+ {@@
+ }
+
+ { TvAlignedDimension }
+
+ TvAlignedDimension = class(TvEntity)
+ public
+ // Mandatory fields
+ BaseLeft, BaseRight, DimensionLeft, DimensionRight: T3DPoint;
+ end;
+
type
TvCustomVectorialWriter = class;
@@ -216,6 +233,8 @@ type
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);
+ // Dimensions
+ procedure AddAlignedDimension(BaseLeft, BaseRight, DimLeft, DimRight: T3DPoint);
{ properties }
property PathCount: Integer read GetPathCount;
property Paths[Index: Cardinal]: TPath read GetPath;
@@ -642,6 +661,19 @@ begin
FEntities.Add(lEllipse);
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;
+ FEntities.Add(lDim);
+end;
+
{@@
Convenience method which creates the correct
writer object for a given vector graphics document format.
diff --git a/packages/fpvectorial/src/fpvtocanvas.pas b/packages/fpvectorial/src/fpvtocanvas.pas
index 6893c3b115..456a656382 100644
--- a/packages/fpvectorial/src/fpvtocanvas.pas
+++ b/packages/fpvectorial/src/fpvtocanvas.pas
@@ -11,7 +11,7 @@ uses
{$ifdef USE_LCL_CANVAS}
Graphics, LCLIntf,
{$else}
- fpcanvas,
+ fpcanvas, fpimage,
{$endif}
fpvectorial;
@@ -25,6 +25,10 @@ procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
implementation
+{$ifndef Windows}
+{$define FPVECTORIALDEBUG}
+{$endif}
+
function Rotate2DPoint(P,Fix :TPoint; alpha:double): TPoint;
var
sinus, cosinus : Extended;
@@ -97,6 +101,17 @@ procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
ADest: TFPCustomCanvas;
{$endif}
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
+
+ function CoordToCanvasX(ACoord: Double): Integer;
+ begin
+ Result := Round(ADestX + AmulX * ACoord);
+ end;
+
+ function CoordToCanvasY(ACoord: Double): Integer;
+ begin
+ Result := Round(ADestY + AmulY * ACoord);
+ end;
+
var
i, j, k: Integer;
PosX, PosY: Integer; // Not modified by ADestX, etc
@@ -113,7 +128,15 @@ var
CurEntity: TvEntity;
CurCircle: TvCircle;
CurEllipse: TvEllipse;
+ //
CurArc: TvCircularArc;
+ FinalStartAngle, FinalEndAngle, tmpAngle: double;
+ BoundsLeft, BoundsTop, BoundsRight, BoundsBottom,
+ IntStartAngle, IntAngleLength, IntTmp: Integer;
+ //
+ CurDim: TvAlignedDimension;
+ Points: array of TPoint;
+ UpperDim, LowerDim: T3DPoint;
begin
{$ifdef FPVECTORIALDEBUG}
WriteLn(':>DrawFPVectorialToCanvas');
@@ -121,6 +144,7 @@ begin
PosX := 0;
PosY := 0;
+ ADest.Brush.Style := bsClear;
ADest.MoveTo(ADestX, ADestY);
@@ -138,17 +162,11 @@ begin
case CurSegment.SegmentType of
stMoveTo:
begin
- ADest.MoveTo(
- Round(ADestX + AMulX * Cur2DSegment.X),
- Round(ADestY + AMulY * Cur2DSegment.Y)
- );
+ ADest.MoveTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
end;
st2DLine, st3DLine:
begin
- ADest.LineTo(
- Round(ADestX + AMulX * Cur2DSegment.X),
- Round(ADestY + AMulY * Cur2DSegment.Y)
- );
+ ADest.LineTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
end;
{ To draw a bezier we need to divide the interval in parts and make
lines between this parts }
@@ -164,9 +182,7 @@ 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(
- Round(ADestX + AMulX * CurX),
- Round(ADestY + AMulY * CurY));
+ ADest.LineTo(CoordToCanvasX(CurX), CoordToCanvasY(CurY));
end;
PosX := Round(Cur2DBSegment.X);
PosY := Round(Cur2DBSegment.Y);
@@ -183,10 +199,10 @@ begin
begin
CurCircle := CurEntity as TvCircle;
ADest.Ellipse(
- 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))
+ 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
@@ -198,16 +214,155 @@ begin
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.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)
+ BoundsLeft, BoundsTop, BoundsRight, BoundsBottom,
+ IntStartAngle, IntAngleLength
);
+ // 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
+ 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
+ {$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]));
+ 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]));
+ 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;
@@ -215,10 +370,16 @@ begin
for i := 0 to ASource.GetTextCount - 1 do
begin
CurText := ASource.GetText(i);
- ADest.Font.Height := Round(AmulY * CurText.FontSize);
+ ADest.Font.Size := Round(AmulX * CurText.FontSize);
ADest.Pen.Style := psSolid;
+ {$ifdef USE_LCL_CANVAS}
ADest.Pen.Color := clBlack;
- ADest.TextOut(Round(CurText.X), Round(CurText.Y), CurText.Value);
+ {$else}
+ ADest.Pen.FPColor := colBlack;
+ {$endif}
+ ADest.Brush.Style := bsClear;
+ LowerDim.Y := CurText.Y + CurText.FontSize;
+ ADest.TextOut(CoordToCanvasX(CurText.X), CoordToCanvasY(LowerDim.Y), CurText.Value);
end;
{$ifdef FPVECTORIALDEBUG}