fpvectorial: Adds support for radial/diametral dimensions in both generic fpvectorial and in the DXF reader

git-svn-id: trunk@39186 -
This commit is contained in:
sekelsenmat 2012-10-29 11:46:52 +00:00
parent 2c2ab8a509
commit 74b95eaefd
3 changed files with 179 additions and 4 deletions

View File

@ -1138,7 +1138,7 @@ Group codes Description
220, 230 DXF: Y and Z values of extrusion direction (optional)
3 Dimension style name
Aligned Dimension Group Codes
*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
@ -1152,6 +1152,18 @@ Aligned Dimension Group Codes
| |
| |
X->14,24 X->13,23
*Radial and Diameter Dimension Group Codes
http://www.autodesk.com/techpubs/autocad/acadr14/dxf/index.htm
100 Subclass marker (AcDbRadialDimension or AcDbDiametricDimension)
15 Definition point for diameter, radius, and angular dimensions (in WCS). DXF: X value; APP: 3D point
25, 35 DXF: Y and Z values of definition point for diameter, radius, and angular dimensions (in WCS).
40 Leader length for radius and diameter dimensions.
The point (15,25,35) specifies the first point of the dimension line on the circle/arc
and the point (10,20,30) specifies the point opposite the first point.
The point (11,21,31) specifies the midpoint of the dimension text.
}
procedure TvDXFVectorialReader.ReadENTITIES_DIMENSION(ATokens: TDXFTokens;
AData: TvVectorialPage; ADoc: TvVectorialDocument);
@ -1160,7 +1172,10 @@ var
i: Integer;
// DIMENSION
BaseLeft, BaseRight, DimensionRight, DimensionLeft, TmpPoint: T3DPoint;
lCenter, Dim1, Dim5: T3DPoint;
IsAlignedDimension: Boolean = False;
IsRadialDimension: Boolean = False;
IsDiametricDimension: Boolean = False;
begin
// Initial values
BaseLeft.X := 0;
@ -1178,7 +1193,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] then
if CurToken.GroupCode in [10, 20, 30, 11, 21, 31, 13, 23, 33, 14, 24, 34, 15, 25, 35] then
begin
CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
end;
@ -1187,15 +1202,23 @@ begin
10: DimensionRight.X := CurToken.FloatValue;
20: DimensionRight.Y := CurToken.FloatValue;
30: DimensionRight.Z := CurToken.FloatValue;
11: Dim1.X := CurToken.FloatValue;
21: Dim1.Y := CurToken.FloatValue;
31: Dim1.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;
15: Dim5.X := CurToken.FloatValue;
25: Dim5.Y := CurToken.FloatValue;
35: Dim5.Z := CurToken.FloatValue;
100:
begin
if CurToken.StrValue = 'AcDbAlignedDimension' then IsAlignedDimension := True;
if CurToken.StrValue = 'AcDbAlignedDimension' then IsAlignedDimension := True
else if CurToken.StrValue = 'AcDbRadialDimension' then IsRadialDimension := True
else if CurToken.StrValue = 'AcDbDiametricDimension' then IsDiametricDimension := True;
end;
end;
end;
@ -1257,6 +1280,28 @@ begin
end;
AData.AddAlignedDimension(BaseLeft, BaseRight, DimensionLeft, DimensionRight);
end
// Radius and Diameters are very similar
else if IsRadialDimension or IsDiametricDimension then
begin
if IsRadialDimension then
begin
lCenter.X := DimensionRight.X;
lCenter.Y := DimensionRight.Y;
DimensionLeft.X := Dim5.X;
DimensionLeft.Y := Dim5.Y;
end
else
begin
lCenter.X := Dim1.X;
lCenter.Y := Dim1.Y;
DimensionLeft.X := Dim5.X;
DimensionLeft.Y := Dim5.Y;
DimensionRight.X := DimensionRight.X;
DimensionRight.Y := DimensionRight.Y;
end;
AData.AddRadialDimension(IsDiametricDimension, lCenter, DimensionLeft, DimensionRight);
end;
end;

View File

@ -337,6 +337,21 @@ type
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); override;
end;
{@@
}
{ TvRadialDimension }
TvRadialDimension = class(TvEntityWithPen)
public
// Mandatory fields
IsDiameter: Boolean; // If false, it is a radius, if true, it is a diameter
Center, DimensionLeft, DimensionRight: T3DPoint; // Diameter uses both, Radius uses only DImensionLeft
procedure Render(ADest: TFPCustomCanvas; ADestX: Integer = 0;
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); override;
end;
{@@
Vectorial images can contain raster images inside them and this entity
represents this.
@ -614,6 +629,7 @@ type
function AddInsert(AX, AY, AZ: Double; ABlock: TvBlock): TvInsert;
// Dimensions
procedure AddAlignedDimension(BaseLeft, BaseRight, DimLeft, DimRight: T3DPoint);
procedure AddRadialDimension(AIsDiameter: Boolean; ACenter, ADimLeft, ADimRight: T3DPoint);
//
function AddPoint(AX, AY, AZ: Double): TvPoint;
{ Debug methods }
@ -1615,6 +1631,93 @@ begin
ADest.TextOut(CoordToCanvasX(CurDim.BaseLeft.X), CoordToCanvasY(CurDim.BaseLeft.Y), 'BL');}
end;
{ TvRadialDimension }
procedure TvRadialDimension.Render(ADest: TFPCustomCanvas; ADestX: Integer;
ADestY: Integer; AMulX: Double; AMulY: Double);
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
Points: array of TPoint;
lAngle, lRadius: Double;
{$ifdef USE_LCL_CANVAS}
ALCLDest: TCanvas absolute ADest;
{$endif}
begin
// The size of the radius of the circle
lRadius := sqrt(sqr(Center.X - DimensionLeft.X) + sqr(Center.Y - DimensionLeft.Y));
// The angle to the first dimension
lAngle := arctan((DimensionLeft.Y - Center.Y) / (DimensionLeft.X - Center.X));
// Get an arrow in the right part of the circle
SetLength(Points, 3);
ADest.Brush.FPColor := colBlack;
ADest.Brush.Style := bsSolid;
Points[0] := Point(CoordToCanvasX(Center.X + lRadius), CoordToCanvasY(Center.Y));
Points[1] := Point(CoordToCanvasX(Center.X + lRadius*0.8), CoordToCanvasY(Center.Y - lRadius*0.1));
Points[2] := Point(CoordToCanvasX(Center.X + lRadius*0.8), CoordToCanvasY(Center.Y + lRadius*0.1));
// Now rotate it to the actual position
Points[0] := Rotate2DPoint(Points[0], Point(CoordToCanvasX(Center.X), CoordToCanvasY(Center.Y)), lAngle);
Points[1] := Rotate2DPoint(Points[1], Point(CoordToCanvasX(Center.X), CoordToCanvasY(Center.Y)), lAngle);
Points[2] := Rotate2DPoint(Points[2], Point(CoordToCanvasX(Center.X), CoordToCanvasY(Center.Y)), lAngle);
if not IsDiameter then
begin
// Basic line
ADest.MoveTo(CoordToCanvasX(Center.X), CoordToCanvasY(Center.Y));
ADest.LineTo(CoordToCanvasX(DimensionLeft.X), CoordToCanvasY(DimensionLeft.Y));
// Draw the arrow
ADest.Polygon(Points);
ADest.Brush.Style := bsClear;
// Dimension text
Points[0].X := CoordToCanvasX(Center.X);
Points[0].Y := CoordToCanvasY(Center.Y);
ADest.Font.Size := 10;
ADest.TextOut(Points[0].X, Points[0].Y, Format('%.1f', [lRadius]));
end
else
begin
// Basic line
ADest.MoveTo(CoordToCanvasX(DimensionLeft.X), CoordToCanvasY(DimensionLeft.Y));
ADest.LineTo(CoordToCanvasX(DimensionRight.X), CoordToCanvasY(DimensionRight.Y));
// Draw the first arrow
ADest.Polygon(Points);
ADest.Brush.Style := bsClear;
// And the second
Points[0] := Point(CoordToCanvasX(Center.X + lRadius), CoordToCanvasY(Center.Y));
Points[1] := Point(CoordToCanvasX(Center.X + lRadius*0.8), CoordToCanvasY(Center.Y - lRadius*0.1));
Points[2] := Point(CoordToCanvasX(Center.X + lRadius*0.8), CoordToCanvasY(Center.Y + lRadius*0.1));
// Now rotate it to the actual position
Points[0] := Rotate2DPoint(Points[0], Point(CoordToCanvasX(Center.X), CoordToCanvasY(Center.Y)), lAngle + Pi);
Points[1] := Rotate2DPoint(Points[1], Point(CoordToCanvasX(Center.X), CoordToCanvasY(Center.Y)), lAngle + Pi);
Points[2] := Rotate2DPoint(Points[2], Point(CoordToCanvasX(Center.X), CoordToCanvasY(Center.Y)), lAngle + Pi);
//
ADest.Polygon(Points);
ADest.Brush.Style := bsClear;
// Dimension text
Points[0].X := CoordToCanvasX(Center.X);
Points[0].Y := CoordToCanvasY(Center.Y);
ADest.Font.Size := 10;
ADest.TextOut(Points[0].X, Points[0].Y, Format('%.1f', [lRadius * 2]));
end;
SetLength(Points, 0);
end;
{ TvRasterImage }
procedure TvRasterImage.InitializeWithConvertionOf3DPointsToHeightMap(APage: TvVectorialPage; AWidth, AHeight: Integer);
@ -2733,6 +2836,19 @@ begin
AddEntity(lDim);
end;
procedure TvVectorialPage.AddRadialDimension(AIsDiameter: Boolean; ACenter,
ADimLeft, ADimRight: T3DPoint);
var
lDim: TvRadialDimension;
begin
lDim := TvRadialDimension.Create;
lDim.IsDiameter := AIsDiameter;
lDim.Center := ACenter;
lDim.DimensionLeft := ADimLeft;
lDim.DimensionRight := ADimRight;
AddEntity(lDim);
end;
function TvVectorialPage.AddPoint(AX, AY, AZ: Double): TvPoint;
var
lPoint: TvPoint;

View File

@ -46,7 +46,8 @@ procedure EllipticalArcToBezier(Xc, Yc, Rx, Ry, startAngle, endAngle: Double; va
procedure CircularArcToBezier(Xc, Yc, R, startAngle, endAngle: Double; var P1, P2, P3, P4: T3DPoint);
procedure AddBezierToPoints(P1, P2, P3, P4: T3DPoint; var Points: TPointsArray);
procedure ConvertPathToPoints(APath: TPath; ADestX, ADestY: Integer; AMulX, AMulY: Double; var Points: TPointsArray);
function Rotate2DPoint(P,Fix :TPoint; alpha:double): TPoint;
function Rotate2DPoint(P, Fix: TPoint; alpha:double): TPoint;
function Rotate3DPointInXY(P, Fix: T3DPoint; alpha:double): T3DPoint;
// LCL-related routines
{$ifdef USE_LCL_CANVAS}
function ConvertPathToRegion(APath: TPath; ADestX, ADestY: Integer; AMulX, AMulY: Double): HRGN;
@ -274,6 +275,7 @@ begin
end;
end;
// Rotates a point P around Fix
function Rotate2DPoint(P,Fix :TPoint; alpha:double): TPoint;
var
sinus, cosinus : Extended;
@ -285,6 +287,18 @@ begin
result.y := Round(-p.x*sinus + p.y*cosinus) + Fix.y;
end;
// Rotates a point P around Fix
function Rotate3DPointInXY(P, Fix: T3DPoint; alpha:double): T3DPoint;
var
sinus, cosinus : Extended;
begin
SinCos(alpha, sinus, cosinus);
P.x := P.x - Fix.x;
P.y := P.y - Fix.y;
result.x := Round(p.x*cosinus + p.y*sinus) + fix.x;
result.y := Round(-p.x*sinus + p.y*cosinus) + Fix.y;
end;
{$ifdef USE_LCL_CANVAS}
function ConvertPathToRegion(APath: TPath; ADestX, ADestY: Integer; AMulX, AMulY: Double): HRGN;
var