diff options
| author | florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2011-04-10 19:20:48 +0000 |
|---|---|---|
| committer | florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2011-04-10 19:20:48 +0000 |
| commit | 160cc1e115eeb75638dce6effdd16b2bc810ddb4 (patch) | |
| tree | b791a95695a7cf674e61a6153139c6f9c6c491fa /packages/fpvectorial | |
| parent | 3843727e74b31bbf2a34e7e3b89ee422269f770e (diff) | |
| parent | 413a6aa6469e6c297780217a27ca91363c637944 (diff) | |
| download | fpc-avr.tar.gz | |
* rebase to trunk@17295avr
git-svn-id: http://svn.freepascal.org/svn/fpc/branches/avr@17296 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'packages/fpvectorial')
| -rw-r--r-- | packages/fpvectorial/src/avisocncgcodewriter.pas | 44 | ||||
| -rw-r--r-- | packages/fpvectorial/src/dxfvectorialreader.pas | 270 | ||||
| -rw-r--r-- | packages/fpvectorial/src/fpvectorial.pas | 32 | ||||
| -rw-r--r-- | packages/fpvectorial/src/fpvtocanvas.pas | 209 |
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} |
