Fixes compiling avisocncvectorialwriter, adds a dimension entity and multiple improvements to fpvtocanvas and the DXF vectorial reader

git-svn-id: trunk@17092 -
This commit is contained in:
sekelsenmat 2011-03-08 14:28:26 +00:00
parent 5aea0bc565
commit c0f254d706
4 changed files with 515 additions and 44 deletions

View File

@ -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;

View File

@ -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,10 +593,175 @@ 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
@ -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;

View File

@ -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.

View File

@ -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);
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)
);
{$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(
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}