diff options
Diffstat (limited to 'packages/fpvectorial/src/fpvtocanvas.pas')
| -rw-r--r-- | packages/fpvectorial/src/fpvtocanvas.pas | 209 |
1 files changed, 185 insertions, 24 deletions
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} |
