Browse Source

fpvectorial: Removes unused Z coordinates and makes the entity classes smarter, adds support for searching for elements

git-svn-id: trunk@18258 -
sekelsenmat 14 years ago
parent
commit
cc8854b0bc

+ 6 - 8
packages/fpvectorial/src/dxfvectorialreader.pas

@@ -590,7 +590,7 @@ begin
   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, LColor);
+  AData.AddCircularArc(CenterX, CenterY, Radius, StartAngle, EndAngle, LColor);
 end;
 
 {
@@ -638,8 +638,7 @@ begin
   CircleCenterX := CircleCenterX - DOC_OFFSET.X;
   CircleCenterY := CircleCenterY - DOC_OFFSET.Y;
 
-  AData.AddCircle(CircleCenterX, CircleCenterY,
-    CircleCenterZ, CircleRadius);
+  AData.AddCircle(CircleCenterX, CircleCenterY, CircleRadius);
 end;
 
 {
@@ -845,7 +844,7 @@ begin
   CenterY := CenterY - DOC_OFFSET.Y;
 
   //
-  AData.AddEllipse(CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle);
+  AData.AddEllipse(CenterX, CenterY, MajorHalfAxis, MinorHalfAxis, Angle);
 end;
 
 {
@@ -916,7 +915,7 @@ begin
   PosY := PosY - DOC_OFFSET.Y;
 
   //
-  AData.AddText(PosX, PosY, PosZ, '', Round(FontSize), Str);
+  AData.AddText(PosX, PosY, '', Round(FontSize), Str);
 end;
 
 {.$define FPVECTORIALDEBUG_LWPOLYLINE}
@@ -1141,7 +1140,7 @@ begin
   PosY := PosY - DOC_OFFSET.Y;
 
   //
-  AData.AddText(PosX, PosY, PosZ, '', Round(FontSize), Str);
+  AData.AddText(PosX, PosY, '', Round(FontSize), Str);
 end;
 
 procedure TvDXFVectorialReader.ReadENTITIES_POINT(ATokens: TDXFTokens;
@@ -1179,8 +1178,7 @@ begin
   CircleCenterX := CircleCenterX - DOC_OFFSET.X;
   CircleCenterY := CircleCenterY - DOC_OFFSET.Y;
 
-  AData.AddCircle(CircleCenterX, CircleCenterY,
-    CircleCenterZ, CircleRadius);
+  AData.AddCircle(CircleCenterX, CircleCenterY, CircleRadius);
 end;
 
 function TvDXFVectorialReader.GetCoordinateValue(AStr: shortstring): Double;

+ 102 - 50
packages/fpvectorial/src/fpvectorial.pas

@@ -139,6 +139,8 @@ type
     X3, Y3, Z3: Double;
   end;
 
+  TvFindEntityResult = (vfrNotFound, vfrFound, vfrSubpartFound);
+
   { Now all elements }
 
   {@@
@@ -150,6 +152,7 @@ type
 
   TvEntity = class
   public
+    X, Y: Double;
     {@@ The global Pen for the entire entity. In the case of paths, individual
         elements might be able to override this setting. }
     Pen: TvPen;
@@ -159,6 +162,7 @@ type
     constructor Create; virtual;
     procedure CalculateBoundingBox(var ALeft, ATop, ARight, ABottom: Double); virtual;
     procedure ExpandBoundingBox(var ALeft, ATop, ARight, ABottom: Double);
+    function TryToSelect(APos: TPoint): TvFindEntityResult; virtual;
   end;
 
   TvClipMode = (vcmNonzeroWindingRule, vcmEvenOddRule);
@@ -174,30 +178,34 @@ type
     procedure PrepareForSequentialReading;
     function Next(): TPathSegment;
     procedure CalculateBoundingBox(var ALeft, ATop, ARight, ABottom: Double); override;
+    procedure AppendSegment(ASegment: TPathSegment);
   end;
 
   {@@
     TvText represents a text entity.
   }
+
+  { TvText }
+
   TvText = class(TvEntity)
   public
-    X, Y, Z: Double; // Z is ignored in 2D formats
     Value: utf8string;
     Font: TvFont;
+    function TryToSelect(APos: TPoint): TvFindEntityResult; override;
   end;
 
   {@@
   }
   TvCircle = class(TvEntity)
   public
-    CenterX, CenterY, CenterZ, Radius: Double;
+    Radius: Double;
   end;
 
   {@@
   }
   TvCircularArc = class(TvEntity)
   public
-    CenterX, CenterY, CenterZ, Radius: Double;
+    Radius: Double;
     {@@ The Angle is measured in degrees in relation to the positive X axis }
     StartAngle, EndAngle: Double;
   end;
@@ -207,7 +215,7 @@ type
   TvEllipse = class(TvEntity)
   public
     // Mandatory fields
-    CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis: Double;
+    MajorHalfAxis, MinorHalfAxis: Double;
     {@@ The Angle is measured in degrees in relation to the positive X axis }
     Angle: Double;
     // Calculated fields
@@ -272,6 +280,8 @@ type
     Name: string;
     // User-Interface information
     ZoomLevel: Double; // 1 = 100%
+    { Selection fields }
+    SelectedvElement: TvEntity;
     { Base methods }
     constructor Create; virtual;
     destructor Destroy; override;
@@ -294,10 +304,11 @@ type
     function  GetPathCount: Integer;
     function  GetEntity(ANum: Cardinal): TvEntity;
     function  GetEntitiesCount: Integer;
+    function  FindAndSelectEntity(Pos: TPoint): TvFindEntityResult;
     { Data removing methods }
     procedure Clear; virtual;
     { Data writing methods }
-    procedure AddEntity(AEntity: TvEntity);
+    function AddEntity(AEntity: TvEntity): Integer;
     procedure AddPathCopyMem(APath: TPath);
     procedure StartPath(AX, AY: Double); overload;
     procedure StartPath(); overload;
@@ -315,11 +326,11 @@ type
     procedure SetPenWidth(AWidth: Integer);
     procedure SetClipPath(AClipPath: TPath; AClipMode: TvClipMode);
     procedure EndPath();
-    procedure AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string); overload;
-    procedure AddText(AX, AY, AZ: Double; AStr: utf8string); overload;
-    procedure AddCircle(ACenterX, ACenterY, ACenterZ, ARadius: Double);
-    procedure AddCircularArc(ACenterX, ACenterY, ACenterZ, ARadius, AStartAngle, AEndAngle: Double; AColor: TFPColor);
-    procedure AddEllipse(CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle: Double);
+    procedure AddText(AX, AY: Double; FontName: string; FontSize: integer; AText: utf8string); overload;
+    procedure AddText(AX, AY: Double; AStr: utf8string); overload;
+    procedure AddCircle(ACenterX, ACenterY, ARadius: Double);
+    procedure AddCircularArc(ACenterX, ACenterY, ARadius, AStartAngle, AEndAngle: Double; AColor: TFPColor);
+    procedure AddEllipse(CenterX, CenterY, MajorHalfAxis, MinorHalfAxis, Angle: Double);
     // Dimensions
     procedure AddAlignedDimension(BaseLeft, BaseRight, DimLeft, DimRight: T3DPoint);
     { properties }
@@ -476,6 +487,19 @@ begin
   Result.Z := 0;
 end;
 
+{ TvText }
+
+function TvText.TryToSelect(APos: TPoint): TvFindEntityResult;
+var
+  lProximityFactor: Integer;
+begin
+  lProximityFactor := 5;
+  if (APos.X > X - lProximityFactor) and (APos.X < X + lProximityFactor)
+    and (APos.Y > Y - lProximityFactor) and (APos.Y < Y + lProximityFactor) then
+    Result := vfrFound
+  else Result := vfrNotFound;
+end;
+
 { TvEntity }
 
 constructor TvEntity.Create;
@@ -505,6 +529,11 @@ begin
   if lBottom > ABottom then ABottom := lBottom;
 end;
 
+function TvEntity.TryToSelect(APos: TPoint): TvFindEntityResult;
+begin
+  Result := vfrNotFound;
+end;
+
 { TvEllipse }
 
 procedure TvEllipse.CalculateBoundingRectangle;
@@ -533,7 +562,7 @@ begin
     tan(t) = b*cot(phi)/a
   }
   t := cotan(-MinorHalfAxis*tan(Angle)/MajorHalfAxis);
-  tmp := CenterX + MajorHalfAxis*cos(t)*cos(Angle) - MinorHalfAxis*sin(t)*sin(Angle);
+  tmp := X + MajorHalfAxis*cos(t)*cos(Angle) - MinorHalfAxis*sin(t)*sin(Angle);
   BoundingRect.Right := Round(tmp);
 end;
 
@@ -791,7 +820,7 @@ begin
   ClearTmpPath();
 end;
 
-procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string);
+procedure TvVectorialDocument.AddText(AX, AY: Double; FontName: string; FontSize: integer; AText: utf8string);
 var
   lText: TvText;
 begin
@@ -799,38 +828,35 @@ begin
   lText.Value := AText;
   lText.X := AX;
   lText.Y := AY;
-  lText.Z := AZ;
   lText.Font.Name := FontName;
   lText.Font.Size := FontSize;
   AddEntity(lText);
 end;
 
-procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; AStr: utf8string);
+procedure TvVectorialDocument.AddText(AX, AY: Double; AStr: utf8string);
 begin
-  AddText(AX, AY, AZ, '', 10, AStr);
+  AddText(AX, AY, '', 10, AStr);
 end;
 
-procedure TvVectorialDocument.AddCircle(ACenterX, ACenterY, ACenterZ, ARadius: Double);
+procedure TvVectorialDocument.AddCircle(ACenterX, ACenterY, ARadius: Double);
 var
   lCircle: TvCircle;
 begin
   lCircle := TvCircle.Create;
-  lCircle.CenterX := ACenterX;
-  lCircle.CenterY := ACenterY;
-  lCircle.CenterZ := ACenterZ;
+  lCircle.X := ACenterX;
+  lCircle.Y := ACenterY;
   lCircle.Radius := ARadius;
   AddEntity(lCircle);
 end;
 
-procedure TvVectorialDocument.AddCircularArc(ACenterX, ACenterY, ACenterZ,
+procedure TvVectorialDocument.AddCircularArc(ACenterX, ACenterY,
   ARadius, AStartAngle, AEndAngle: Double; AColor: TFPColor);
 var
   lCircularArc: TvCircularArc;
 begin
   lCircularArc := TvCircularArc.Create;
-  lCircularArc.CenterX := ACenterX;
-  lCircularArc.CenterY := ACenterY;
-  lCircularArc.CenterZ := ACenterZ;
+  lCircularArc.X := ACenterX;
+  lCircularArc.Y := ACenterY;
   lCircularArc.Radius := ARadius;
   lCircularArc.StartAngle := AStartAngle;
   lCircularArc.EndAngle := AEndAngle;
@@ -838,15 +864,14 @@ begin
   AddEntity(lCircularArc);
 end;
 
-procedure TvVectorialDocument.AddEllipse(CenterX, CenterY, CenterZ,
+procedure TvVectorialDocument.AddEllipse(CenterX, CenterY,
   MajorHalfAxis, MinorHalfAxis, Angle: Double);
 var
   lEllipse: TvEllipse;
 begin
   lEllipse := TvEllipse.Create;
-  lEllipse.CenterX := CenterX;
-  lEllipse.CenterY := CenterY;
-  lEllipse.CenterZ := CenterZ;
+  lEllipse.X := CenterX;
+  lEllipse.Y := CenterY;
   lEllipse.MajorHalfAxis := MajorHalfAxis;
   lEllipse.MinorHalfAxis := MinorHalfAxis;
   lEllipse.Angle := Angle;
@@ -854,10 +879,11 @@ begin
 end;
 
 {@@
-  Don't free the passed TvText because it will be added directly to the list
+  Adds an entity to the document and returns it's current index
 }
-procedure TvVectorialDocument.AddEntity(AEntity: TvEntity);
+function TvVectorialDocument.AddEntity(AEntity: TvEntity): Integer;
 begin
+  Result := FEntities.Count;
   FEntities.Add(Pointer(AEntity));
 end;
 
@@ -933,28 +959,8 @@ begin
 end;
 
 procedure TvVectorialDocument.AppendSegmentToTmpPath(ASegment: TPathSegment);
-var
-  L: Integer;
 begin
-  // Check if we are the first segment in the tmp path
-  if FTmpPath.PointsEnd = nil then
-  begin
-    if FTmpPath.Len <> 0 then
-      Exception.Create('[TvVectorialDocument.AppendSegmentToTmpPath]' + Str_Error_Nil_Path);
-
-    FTmpPath.Points := ASegment;
-    FTmpPath.PointsEnd := ASegment;
-    FTmpPath.Len := 1;
-    Exit;
-  end;
-
-  L := FTmpPath.Len;
-  Inc(FTmpPath.Len);
-
-  // Adds the element to the end of the list
-  FTmpPath.PointsEnd.Next := ASegment;
-  ASegment.Previous := FTmpPath.PointsEnd;
-  FTmpPath.PointsEnd := ASegment;
+  FTmpPath.AppendSegment(ASegment);
 end;
 
 {@@
@@ -1170,6 +1176,27 @@ begin
   Result := FEntities.Count;
 end;
 
+function TvVectorialDocument.FindAndSelectEntity(Pos: TPoint): TvFindEntityResult;
+var
+  lEntity: TvEntity;
+  i: Integer;
+begin
+  Result := vfrNotFound;
+
+  for i := 0 to GetEntitiesCount() - 1 do
+  begin
+    lEntity := GetEntity(i);
+
+    Result := lEntity.TryToSelect(Pos);
+
+    if Result <> vfrNotFound then
+    begin
+      SelectedvElement := lEntity;
+      Exit;
+    end;
+  end;
+end;
+
 {@@
   Clears all data in the document
 }
@@ -1347,6 +1374,31 @@ begin
   end;
 end;
 
+procedure TPath.AppendSegment(ASegment: TPathSegment);
+var
+  L: Integer;
+begin
+  // Check if we are the first segment in the tmp path
+  if PointsEnd = nil then
+  begin
+    if Len <> 0 then
+      Exception.Create('[TPath.AppendSegment] Assertion failed Len <> 0 with PointsEnd = nil');
+
+    Points := ASegment;
+    PointsEnd := ASegment;
+    Len := 1;
+    Exit;
+  end;
+
+  L := Len;
+  Inc(Len);
+
+  // Adds the element to the end of the list
+  PointsEnd.Next := ASegment;
+  ASegment.Previous := PointsEnd;
+  PointsEnd := ASegment;
+end;
+
 finalization
 
   SetLength(GvVectorialFormats, 0);

+ 10 - 10
packages/fpvectorial/src/fpvtocanvas.pas

@@ -65,8 +65,8 @@ begin
   y2 := CurEllipse.BoundingRect.Bottom;
 
   dk := Round(0.654 * Abs(y2-y1));
-  f.x := Round(CurEllipse.CenterX);
-  f.y := Round(CurEllipse.CenterY - 1);
+  f.x := Round(CurEllipse.X);
+  f.y := Round(CurEllipse.Y - 1);
   PointList[0] := Rotate2DPoint(Point(x1, f.y), f, CurEllipse.Angle) ;  // Startpoint
   PointList[1] := Rotate2DPoint(Point(x1,  f.y - dk), f, CurEllipse.Angle);
   //Controlpoint of Startpoint first part
@@ -353,10 +353,10 @@ begin
   begin
     CurCircle := CurEntity as TvCircle;
     ADest.Ellipse(
-      CoordToCanvasX(CurCircle.CenterX - CurCircle.Radius),
-      CoordToCanvasY(CurCircle.CenterY - CurCircle.Radius),
-      CoordToCanvasX(CurCircle.CenterX + CurCircle.Radius),
-      CoordToCanvasY(CurCircle.CenterY + CurCircle.Radius)
+      CoordToCanvasX(CurCircle.X - CurCircle.Radius),
+      CoordToCanvasY(CurCircle.Y - CurCircle.Radius),
+      CoordToCanvasX(CurCircle.X + CurCircle.Radius),
+      CoordToCanvasY(CurCircle.Y + CurCircle.Radius)
       );
   end
   else if CurEntity is TvEllipse then
@@ -370,10 +370,10 @@ begin
     {$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);
+    BoundsLeft := CoordToCanvasX(CurArc.X - CurArc.Radius);
+    BoundsTop := CoordToCanvasY(CurArc.Y - CurArc.Radius);
+    BoundsRight := CoordToCanvasX(CurArc.X + CurArc.Radius);
+    BoundsBottom := CoordToCanvasY(CurArc.Y + CurArc.Radius);
     {if AMulY > 0 then
     begin}
       FinalStartAngle := CurArc.StartAngle;