From 126ca683834ee292bb90c05d6ed5f039a0433211 Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Thu, 18 Aug 2011 09:11:51 +0000 Subject: [PATCH] fpvectorial: Removes unused Z coordinates and makes the entity classes smarter, adds support for searching for elements git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1808 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../fpvectorialsrc/dxfvectorialreader.pas | 14 +- .../fpvviewer/fpvectorialsrc/fpvectorial.pas | 152 ++++++++++++------ .../fpvviewer/fpvectorialsrc/fpvtocanvas.pas | 20 +-- 3 files changed, 118 insertions(+), 68 deletions(-) diff --git a/applications/fpvviewer/fpvectorialsrc/dxfvectorialreader.pas b/applications/fpvviewer/fpvectorialsrc/dxfvectorialreader.pas index 0148ca01e..cd3488082 100644 --- a/applications/fpvviewer/fpvectorialsrc/dxfvectorialreader.pas +++ b/applications/fpvviewer/fpvectorialsrc/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; diff --git a/applications/fpvviewer/fpvectorialsrc/fpvectorial.pas b/applications/fpvviewer/fpvectorialsrc/fpvectorial.pas index 30dc5f3c8..b787dcf7c 100644 --- a/applications/fpvviewer/fpvectorialsrc/fpvectorial.pas +++ b/applications/fpvviewer/fpvectorialsrc/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); diff --git a/applications/fpvviewer/fpvectorialsrc/fpvtocanvas.pas b/applications/fpvviewer/fpvectorialsrc/fpvtocanvas.pas index 72f9bcd53..9791f300e 100644 --- a/applications/fpvviewer/fpvectorialsrc/fpvtocanvas.pas +++ b/applications/fpvviewer/fpvectorialsrc/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;