fpvectorial: Finishes the basic implementation for arc dimensions in fpvectorial base and the DXF reader

git-svn-id: trunk@40601 -
This commit is contained in:
sekelsenmat 2013-03-21 16:18:30 +00:00
parent 2b2a84006d
commit 114a0f6e2d
2 changed files with 95 additions and 24 deletions

View File

@ -1288,7 +1288,9 @@ var
i: Integer;
// DIMENSION
BaseLeft, BaseRight, DimensionRight, DimensionLeft, lCenter, lTextPos, TmpPoint: T3DPoint;
TmpDimensionRight, TmpDimensionLeft: T3DPoint;
Dim0, Dim1, Dim3, Dim4, Dim5, Dim6: T3DPoint;
lAngleLeft, lAngleRight, al, bl, lRadius, lBaskaraDelta, ae, be, ce: Double;
DXFDimensionType: TDXFDimensionType = ddtUnknown;
begin
// Initial values
@ -1308,7 +1310,7 @@ begin
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, 15, 25, 35] then
if CurToken.GroupCode in [10, 20, 30, 11, 21, 31, 13, 23, 33, 14, 24, 34, 15, 25, 35, 16, 26, 36] then
begin
CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
end;
@ -1365,6 +1367,9 @@ begin
{$ifdef FPVECTORIALDEBUG}
// WriteLn(Format('Adding Line from %f,%f to %f,%f', [LineStartX, LineStartY, LineEndX, LineEndY]));
{$endif}
// -----------------------------------------------
// Aligned dimension
// -----------------------------------------------
if DXFDimensionType = ddtAligned then
begin
// Now make sure that we actually that BaseLeft is to the left of BaseRight
@ -1419,7 +1424,9 @@ begin
Result := AData.AddAlignedDimension(BaseLeft, BaseRight, DimensionLeft, DimensionRight, AOnlyCreate);
end
// -----------------------------------------------
// Radius and Diameters are very similar
// -----------------------------------------------
else if DXFDimensionType in [ddtRadial, ddtDiametric] then
begin
if DXFDimensionType = ddtRadial then
@ -1437,17 +1444,72 @@ begin
Result := AData.AddRadialDimension(DXFDimensionType = ddtDiametric, lCenter, DimensionLeft, DimensionRight, AOnlyCreate);
end
// -----------------------------------------------
// A arc dimension
// -----------------------------------------------
else if DXFDimensionType = ddt2LineAngular then
begin
BaseLeft := Dim5;
BaseRight := Dim3;
DimensionLeft := Dim0;
DimensionRight := Dim4;
lCenter := Dim6;
lTextPos := Dim1;
Result := AData.AddArcDimension(BaseLeft, BaseRight, DimensionLeft, DimensionRight, lCenter, lTextPos, AOnlyCreate);
// Sometimes Dim0 and Dim3 are the base, but sometimes Dim4 and Dim5 are the base!
// So we need to check which points are nearer o.O
// I plotted the given points to come to this conclusion
// and it doesn't match the provided example image:
// http://docs.autodesk.com/ACD/2013/RUS/images/GUID-E2F42FD3-2684-4F50-88A9-3AF3A5824FF1-low.png
// but it works. The pairs of points in the same line are 3,4 and 0,5
if Abs(Dim0.X-Dim3.X)+Abs(Dim0.Y-Dim3.Y) < Abs(Dim5.X-Dim4.X)+Abs(Dim5.Y-Dim4.Y) then
begin
BaseLeft := Dim0;
BaseRight := Dim3;
TmpDimensionLeft := Dim5;
TmpDimensionRight := Dim4;
end
else
begin
BaseLeft := Dim4;
BaseRight := Dim5;
TmpDimensionLeft := Dim3;
TmpDimensionRight := Dim0;
end;
// Calculate where the arc hits the left and right lines to obtain DimensionLeft and DimensionRight
// Left line is: Y = al.X + bl
// Circle equation for the arc is (X - BaseLeft.X)^2 + (Y - BaseLeft.Y)^2 = R^2
// This goes to a second degree equation of ae * X^2 + be * X + ce = 0
lAngleLeft := arctan(Abs(BaseLeft.Y-TmpDimensionLeft.Y)/Abs(BaseLeft.X-TmpDimensionLeft.X));
if TmpDimensionLeft.X<BaseLeft.X then lAngleLeft := Pi-lAngleLeft;
lRadius := sqrt(sqr(lCenter.Y-BaseLeft.Y) + sqr(lCenter.X-BaseLeft.X));
al := Tan(lAngleLeft);
bl := BaseLeft.Y - al * BaseLeft.X;
ae := 1 + al*al;
be := -2 * BaseLeft.X + 2 * al * bl - 2 * al * BaseLeft.Y;
ce := sqr(BaseLeft.X)+bl*bl-2*bl*BaseLeft.Y+sqr(BaseLeft.Y)-lRadius*lRadius;
lBaskaraDelta := be*be-4*ae*ce;
// The equation has 2 solutions, get the one nearest to TmpDimension
DimensionLeft.X := (-be+sqrt(lBaskaraDelta)) / (2 * ae);
DimensionLeft.Y := (-be-sqrt(lBaskaraDelta)) / (2 * ae);
if Abs(DimensionLeft.X-TmpDimensionLeft.X)>Abs(DimensionLeft.Y-TmpDimensionLeft.X)then
DimensionLeft.X := DimensionLeft.Y;
DimensionLeft.Y := al * DimensionLeft.X + bl;
lAngleRight := arctan(Abs(BaseRight.Y-TmpDimensionRight.Y)/Abs(BaseRight.X-TmpDimensionRight.X));
if TmpDimensionRight.X<BaseRight.X then lAngleRight := Pi-lAngleRight;
al := Tan(lAngleRight);
bl := BaseRight.Y - al * BaseRight.X;
ae := 1 + al*al;
be := -2 * BaseRight.X + 2 * al * bl - 2 * al * BaseRight.Y;
ce := sqr(BaseRight.X)+bl*bl-2*bl*BaseRight.Y+sqr(BaseRight.Y)-lRadius*lRadius;
lBaskaraDelta := be*be-4*ae*ce;
// The equation has 2 solutions, get the one nearest to TmpDimension
DimensionRight.X := (-be+sqrt(lBaskaraDelta)) / (2 * ae);
DimensionRight.Y := (-be-sqrt(lBaskaraDelta)) / (2 * ae);
if Abs(DimensionRight.X-TmpDimensionRight.X)>Abs(DimensionRight.Y-TmpDimensionRight.X)then
DimensionRight.X := DimensionRight.Y;
DimensionRight.Y := al * DimensionRight.X + bl;
Result := AData.AddArcDimension(180*Abs(lAngleRight-lAngleLeft)/Pi,
lRadius, BaseLeft, BaseRight, DimensionLeft, DimensionRight, lTextPos, AOnlyCreate);
end;
end;

View File

@ -463,8 +463,8 @@ type
TvArcDimension = class(TvEntityWithPen)
public
// Mandatory fields
ArcValue: Double;
DimArcPos, TextPos, BaseLeft, BaseRight, DimensionLeft, DimensionRight: T3DPoint;
ArcValue, ArcRadius: Double; // ArcValue is in degrees
TextPos, BaseLeft, BaseRight, DimensionLeft, DimensionRight: T3DPoint;
procedure Render(ADest: TFPCustomCanvas; ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); override;
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
@ -788,7 +788,7 @@ type
// Dimensions
function AddAlignedDimension(BaseLeft, BaseRight, DimLeft, DimRight: T3DPoint; AOnlyCreate: Boolean = False): TvAlignedDimension;
function AddRadialDimension(AIsDiameter: Boolean; ACenter, ADimLeft, ADimRight: T3DPoint; AOnlyCreate: Boolean = False): TvRadialDimension;
function AddArcDimension(ABaseLeft, ABaseRight, ADimLeft, ADimRight, ADimArcPos, ATextPos: T3DPoint; AOnlyCreate: Boolean = False): TvArcDimension;
function AddArcDimension(AArcValue, AArcRadius: Double; ABaseLeft, ABaseRight, ADimLeft, ADimRight, ATextPos: T3DPoint; AOnlyCreate: Boolean): TvArcDimension;
//
function AddPoint(AX, AY, AZ: Double): TvPoint;
{ Drawing methods }
@ -2374,19 +2374,28 @@ var
Points: array of TPoint;
lAngleLeft, lAngleRight: Double;
lTriangleCenter, lTriangleCorner, lCanvasDim: TPoint;
{$ifdef USE_LCL_CANVAS}
ALCLDest: TCanvas absolute ADest;
{$endif}
begin
ADest.Pen.FPColor := colYellow;//AdjustColorToBackground(colBlack, ARenderInfo);
ADest.Pen.Width := 1;
ADest.Pen.Style := psSolid;
// Get an arrow in the right part of the circle
SetLength(Points, 3);
ADest.Line(CoordToCanvasX(BaseLeft.X), CoordToCanvasY(BaseLeft.Y), CoordToCanvasX(DimensionLeft.X), CoordToCanvasY(DimensionLeft.Y));
ADest.Line(CoordToCanvasX(BaseRight.X), CoordToCanvasY(BaseRight.Y), CoordToCanvasX(DimensionRight.X), CoordToCanvasY(DimensionRight.Y));
// Debug lines
//ADest.Line(CoordToCanvasX(BaseLeft.X), CoordToCanvasY(BaseLeft.Y), CoordToCanvasX(DimensionLeft.X), CoordToCanvasY(DimensionLeft.Y));
//ADest.Line(CoordToCanvasX(BaseRight.X), CoordToCanvasY(BaseRight.Y), CoordToCanvasX(DimensionRight.X), CoordToCanvasY(DimensionRight.Y));
// Now the arc
ALCLDest.Arc(
CoordToCanvasX(BaseLeft.X - ArcRadius), CoordToCanvasY(BaseLeft.Y - ArcRadius),
CoordToCanvasX(BaseLeft.X + ArcRadius), CoordToCanvasY(BaseLeft.Y + ArcRadius),
CoordToCanvasX(DimensionRight.X), CoordToCanvasY(DimensionRight.Y),
CoordToCanvasX(DimensionLeft.X), CoordToCanvasY(DimensionLeft.Y));
// Now the arrows
SetLength(Points, 3);
ADest.Brush.FPColor := AdjustColorToBackground(colBlack, ARenderInfo);
{ ADest.Brush.FPColor := AdjustColorToBackground(colBlack, ARenderInfo);
ADest.Brush.Style := bsSolid;
// Angle of the line of BaseLeft->DimensionLeft
@ -2402,16 +2411,15 @@ begin
lTriangleCorner := Rotate2DPoint(lTriangleCenter, lCanvasDim, - Pi * 10 / 180);
Points[2] := Point(lTriangleCorner.X, lTriangleCorner.Y);
ADest.Polygon(Points);
ADest.Brush.Style := bsClear;
ADest.Brush.Style := bsClear; }
// Dimension text
{ Points[0].X := CoordToCanvasX((DimensionLeft.X+DimensionRight.X)/2);
Points[0].Y := CoordToCanvasY(DimensionLeft.Y);
LowerDim.X := DimensionRight.X-DimensionLeft.X;
Points[0].X := CoordToCanvasX(TextPos.X);
Points[0].Y := CoordToCanvasY(TextPos.Y);
ADest.Font.Size := 10;
ADest.Font.Orientation := 0;
ADest.Font.FPColor := AdjustColorToBackground(colBlack, ARenderInfo);
ADest.TextOut(Points[0].X, Points[0].Y-Round(ADest.Font.Size*1.5), Format('%.1f', [LowerDim.X]));}
ADest.Font.FPColor := colYellow;//AdjustColorToBackground(colBlack, ARenderInfo);
ADest.TextOut(Points[0].X, Points[0].Y-Round(ADest.Font.Size*1.5), Format('%.1f', [ArcValue]));
end;
function TvArcDimension.GenerateDebugTree(ADestRoutine: TvDebugAddItemProc;
@ -2422,8 +2430,8 @@ var
begin
Result := inherited GenerateDebugTree(ADestRoutine, APageItem);
// Add the font debug info in a sub-item
lStr := Format('[TvArcDimension] DimArcPos=%f %f TextPos=%f %f BaseLeft=%f %f BaseRight=%f %f DimensionLeft=%f %f DimensionRight=%f %f',
[DimArcPos.X, DimArcPos.Y,
lStr := Format('[TvArcDimension] ArcValue=%f ArcRadius=%f TextPos=%f %f BaseLeft=%f %f BaseRight=%f %f DimensionLeft=%f %f DimensionRight=%f %f',
[ArcValue, ArcRadius,
TextPos.X, TextPos.Y,
BaseLeft.X, BaseLeft.Y,
BaseRight.X, BaseRight.Y,
@ -3707,7 +3715,7 @@ begin
if not AOnlyCreate then AddEntity(lDim);
end;
function TvVectorialPage.AddArcDimension(ABaseLeft, ABaseRight, ADimLeft, ADimRight, ADimArcPos, ATextPos: T3DPoint; AOnlyCreate: Boolean): TvArcDimension;
function TvVectorialPage.AddArcDimension(AArcValue, AArcRadius: Double; ABaseLeft, ABaseRight, ADimLeft, ADimRight, ATextPos: T3DPoint; AOnlyCreate: Boolean): TvArcDimension;
var
lDim: TvArcDimension;
begin
@ -3716,7 +3724,8 @@ begin
lDim.BaseRight := ABaseRight;
lDim.DimensionLeft := ADimLeft;
lDim.DimensionRight := ADimRight;
lDim.DimArcPos := ADimArcPos;
lDim.ArcRadius := AArcRadius;
lDim.ArcValue := AArcValue;
lDim.TextPos := ATextPos;
Result := lDim;
if not AOnlyCreate then AddEntity(lDim);