LazMapViewer: Track segment marks and GPX track loading. TryStrToGpxColor fix.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9290 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
alpine-a110 2024-03-28 14:15:23 +00:00
parent 6a13ae7fb3
commit 8eaa889f85
3 changed files with 181 additions and 37 deletions

View File

@ -39,29 +39,51 @@ type
property Width: Double read FWidth write SetWidth; // Line width in mm
end;
{ TTrackSegmentExtraData }
{ TSegmentExtraData }
TTrackSegmentExtraData = class(TObject)
TSegmentExtraData = class(TObject)
public
type TSegmentMark = (smNone, smStart, smMid, smEnd);
private
FMark: TSegmentMark;
public
constructor Create(AMark: TSegmentMark);
class function MarkOf(const APoint: TObject): TSegmentMark;
property Mark: TSegmentMark read FMark write FMark;
end;
implementation
{ TTrackSegmentExtraData }
uses
mvGpsObj;
constructor TTrackSegmentExtraData.Create(AMark: TSegmentMark);
{ TSegmentExtraData }
constructor TSegmentExtraData.Create(AMark: TSegmentMark);
begin
inherited Create;
FMark := AMark;
end;
// Can be invoked with APoint.Extradata or with APoint itself
class function TSegmentExtraData.MarkOf(const APoint: TObject): TSegmentMark;
begin
// Quick check for Nil (APoint.Extradata, APoint)
if not Assigned(APoint) then
Result := smNone
// Check for non-nil TSegmentExtraData (APoint.Extradata)
else if (APoint is Self) then
Result := TSegmentExtraData(APoint).Mark
// Check for non-nil object with a non-nil TSegmentExtraData (APoint)
else if (APoint is TGPSObj) and Assigned(TGPSObj(APoint).ExtraData) and
(TGPSObj(APoint).ExtraData is Self)
then
Result := TSegmentExtraData(TGPSObj(APoint).ExtraData).Mark
else // None of the above
Result := smNone;
end;
{ TDrawingExtraData }
constructor TDrawingExtraData.Create(aId: integer);

View File

@ -55,7 +55,7 @@ implementation
uses
Math,
mvExtraData;
mvExtraData, Graphics;
var
PointSettings: TFormatSettings;
@ -192,30 +192,34 @@ begin
end;
function TryStrToGpxColor(AGpxText: String; out AColor: LongInt): Boolean;
type
PGpxColorRec = ^TGpxColorRec;
TGpxColorRec = record
r: array[0..1] of char;
g: array[0..1] of char;
b: array[0..1] of char;
end;
var
rv, gv, bv: Integer;
ch: Char;
//type
// PGpxColorRec = ^TGpxColorRec;
// TGpxColorRec = record
// r: array[0..1] of char;
// g: array[0..1] of char;
// b: array[0..1] of char;
// end;
//var
// rv, gv, bv: Integer;
// ch: Char;
begin
Result := false;
if Length(AGpxText) <> 6 then
exit;
for ch in AGpxText do
if not (ch in ['0'..'9', 'A'..'F', 'a'..'f']) then exit;
//for ch in AGpxText do
// if not (ch in ['0'..'9', 'A'..'F', 'a'..'f']) then exit;
with PGpxColorRec(@AGpxText[1])^ do begin
rv := (ord(r[0]) - ord('0')) * 16 + ord(r[1]) - ord('0');
gv := (ord(g[0]) - ord('0')) * 16 + ord(g[1]) - ord('0');
bv := (ord(b[0]) - ord('0')) * 16 + ord(b[1]) - ord('0');
end;
AColor := rv + gv shl 8 + bv shl 16;
Result := true;
(* Doesn't work for letters! *)
//with PGpxColorRec(@AGpxText[1])^ do begin
// rv := (ord(r[0]) - ord('0')) * 16 + ord(r[1]) - ord('0');
// gv := (ord(g[0]) - ord('0')) * 16 + ord(g[1]) - ord('0');
// bv := (ord(b[0]) - ord('0')) * 16 + ord(b[1]) - ord('0');
//end;
//AColor := rv + gv shl 8 + bv shl 16;
Result := TryStrToInt('$' + AGpxText, AColor);
if Result then
AColor := ((AColor and $FF) shl 16) + (AColor and $FF00) + ((AColor and $FF0000) shr 16);
end;
@ -296,6 +300,50 @@ var
CreateTextElement(Result, 'time', DateToISO8601(APOI.DateTime));
end;
function CreateTrack(AName: String; ATrack: TGPSTrack): TDOMElement;
var
Seg, LineEx, Ex: TDOMElement;
L: LongInt;
procedure CreateSegments;
var
P: TGPSObj;
begin
for P in ATrack.AllObjs do
begin
Seg.AppendChild(CreatePoint('trkpt', TGPSPoint(P)));
if TSegmentExtraData.MarkOf(P) = smEnd then
begin
Seg := Doc.CreateElement('trkseg');
Result.AppendChild(Seg);
end;
end;
end;
begin
Result := Doc.CreateElement(AName);
if ATrack.Name <> '' then
CreateTextElement(Result, 'name', ATrack.Name);
if Assigned(ATrack.ExtraData) and (ATrack.ExtraData is TTrackExtraData) then
with TTrackExtraData(ATrack.ExtraData) do
begin
Ex := Doc.CreateElement('extensions');
LineEx := Doc.CreateElement('line');
Ex.AppendChild(LineEx);
Result.AppendChild(Ex);
L := ColorToRGB(Color);
L := ((L and $FF) shl 16) + (L and $FF00) + ((L and $FF0000) shr 16);
CreateTextElement(LineEx, 'color', L.ToHexString(6));
CreateTextElement(LineEx, 'width', Width.ToString);
end;
if ATrack.Points.Count > 0 then
begin
Seg := Doc.CreateElement('trkseg');
Result.AppendChild(Seg);
CreateSegments;
end;
end;
begin
Doc := TXMLDocument.Create;
try
@ -314,6 +362,8 @@ begin
else if O is TGPSPoint then
RootNode.AppendChild(CreatePoint('wpt', TGPSPoint(O)))
else if O is TGPSTrack then
RootNode.AppendChild(CreateTrack('trk', TGPSTrack(O)))
else
{TODO};
end;
WriteXMLFile(doc, AStream);
@ -531,7 +581,7 @@ begin
ANode := ANode.NextSibling;
end;
if Assigned(gpsPt) then // Mark the last point of the segment
gpsPt.ExtraData := TTrackSegmentExtraData.Create(smEnd);
gpsPt.ExtraData := TSegmentExtraData.Create(smEnd);
end;
procedure TGpxReader.ReadWayPoints(ANode: TDOMNode; AList: TGpsObjectList);

View File

@ -25,7 +25,7 @@ uses
Classes, SysUtils, Controls, GraphType, Graphics, FPImage, IntfGraphics,
Forms, ImgList, LCLVersion,
MvTypes, MvGPSObj, MvEngine, MvMapProvider, MvDownloadEngine, MvDrawingEngine,
mvCache;
mvCache, mvExtraData;
Type
@ -224,10 +224,16 @@ type
{ TMapTrackPoint }
TMapTrackPoint = class(TMapPoint)
private
FMark: TSegmentExtraData.TSegmentMark;
function MarkIsStored: Boolean;
procedure SetMark(AValue: TSegmentExtraData.TSegmentMark);
protected
function GPSTrack: TGPSTrack;
function CreatePoint: TGPSPoint; override;
procedure DestroyPoint; override;
published
property Mark: TSegmentExtraData.TSegmentMark read FMark write SetMark stored MarkIsStored;
end;
{ TMapTrackPoints }
@ -285,6 +291,9 @@ type
FOnDrawTrack: TMapTrackDrawEvent;
function GetGPSObj: TGPSObj; override;
function GetPoints: TMapTrackPoints;
procedure SetLineColor(AValue: TColor);
procedure SetLineWidth(AValue: Double);
procedure ExtraData;
procedure SetOnDrawTrack(AValue: TMapTrackDrawEvent);
procedure SetPoints(AValue: TMapTrackPoints);
protected
@ -295,8 +304,8 @@ type
procedure ItemChanged; override;
published
//property DateTime: TDateTime read GetDateTime write FDateTime;
property LineColor: TColor read FLineColor write FLineColor default clDefault;
property LineWidth: Double read FLineWidth write FLineWidth;
property LineColor: TColor read FLineColor write SetLineColor default clDefault;
property LineWidth: Double read FLineWidth write SetLineWidth;
property Points: TMapTrackPoints read GetPoints write SetPoints;
property OnDrawTrack: TMapTrackDrawEvent read FOnDrawTrack write SetOnDrawTrack;
end;
@ -574,7 +583,7 @@ implementation
uses
GraphMath, FileUtil, LazLoggerBase, Types, Math,
mvJobQueue, mvExtraData, mvDLEFpc,
mvJobQueue, mvDLEFpc,
{$IFDEF MSWINDOWS}
mvDLEWin,
{$ENDIF}
@ -636,6 +645,26 @@ begin
//FPoint.Free;
end;
function TMapTrackPoint.MarkIsStored: Boolean;
begin
Result := FMark <> smNone;
end;
procedure TMapTrackPoint.SetMark(AValue: TSegmentExtraData.TSegmentMark);
begin
if FMark = AValue then
Exit;
FMark := AValue;
if (AValue = smNone) then
FPoint.ExtraData.Free
else
begin
if not Assigned(FPoint.ExtraData)
then FPoint.ExtraData := TSegmentExtraData.Create(AValue)
else TSegmentExtraData(FPoint.ExtraData).Mark := AValue;
end;
end;
function TMapTrackPoint.GPSTrack: TGPSTrack;
begin
Result := Nil;
@ -735,6 +764,36 @@ begin
Result := FPoints;
end;
procedure TMapTrack.SetLineColor(AValue: TColor);
begin
if FLineColor = AValue then Exit;
FLineColor := AValue;
ExtraData;
end;
procedure TMapTrack.SetLineWidth(AValue: Double);
begin
if FLineWidth = AValue then Exit;
FLineWidth := AValue;
ExtraData;
end;
procedure TMapTrack.ExtraData;
begin
if (FLineColor = clDefault) and (FLineWidth < 0.01) then
begin
FTrack.ExtraData.Free; // No need, aId?
FTrack.ExtraData := Nil;
end
else
begin
if not Assigned(FTrack.ExtraData) then
FTrack.ExtraData := TTrackExtraData.Create(-1); // aId?
TTrackExtraData(FTrack.ExtraData).Color := FLineColor;
TTrackExtraData(FTrack.ExtraData).Width := FLineWidth;
end;
end;
procedure TMapTrack.SetPoints(AValue: TMapTrackPoints);
begin
FPoints.Assign(AValue);
@ -768,6 +827,7 @@ end;
procedure TMapTrack.ItemChanged;
begin
FTrack.Name := Caption;
FTrack.LineColor := LineColor;
FTrack.LineWidth := LineWidth;
FTrack.Visible := Visible;
@ -1195,12 +1255,10 @@ begin
FVisible := True;
FTag := 0;
DebugLn('TMapLayer.Create 1');
FPointsOfInterest := TPointsOfInterest.Create(Self);
FTracks := TMapTracks.Create(Self);
FComboLayer := TGPSComboLayer.Create;
View.GPSItems.Add(FComboLayer, _TILELAYERS_ID_, Self.Index - LAYERS_ZOFFS);
DebugLn('TMapLayer.Create X');
end;
destructor TMapLayer.Destroy;
@ -1232,6 +1290,8 @@ procedure TMapLayer.AssignFromGPSList(AList: TGPSObjectList);
P: TGPSPoint;
begin
with Tracks.Add as TMapTrack do
begin
Caption := ATrack.Name;
for I := 0 to Pred(ATrack.Points.Count) do
with Points.Add as TMapTrackPoint do
begin
@ -1241,7 +1301,15 @@ procedure TMapLayer.AssignFromGPSList(AList: TGPSObjectList);
Latitude := P.Lat;
Elevation := P.Elevation;
DateTime := P.DateTime;
if ATrack.Points[I].ExtraData is TSegmentExtraData then
Mark := TSegmentExtraData(ATrack.Points[I].ExtraData).Mark;
end;
if ATrack.ExtraData is TTrackExtraData then
begin
LineWidth := TTrackExtraData(ATrack.ExtraData).Width;
LineColor := TTrackExtraData(ATrack.ExtraData).Color;
end;
end;
end;
var
@ -1250,6 +1318,7 @@ begin
if not Assigned(AList) then
Exit;
PointsOfInterest.Clear;
Tracks.Clear;
for I := 0 to Pred(AList.Count) do
if AList[I] is TGPSPoint then
AddPoint(TGPSPoint(AList[I]))
@ -1907,7 +1976,7 @@ var
I, L, T, WS: Integer;
ClipRect: TRect;
iPt1, iPt2, iPt3, iPt4: TPoint;
ToEast: Boolean;
ToEast, EndSegm: Boolean;
pt1, pt2: TRealPoint;
trkColor: TColor;
trkWidth: Integer;
@ -1945,6 +2014,7 @@ begin
pt1 := trk.Points[0].RealPoint;
iPt1 := Engine.LonLatToScreen(pt1);
EndSegm := TSegmentExtraData.MarkOf(trk.Points[0].ExtraData) = smEnd;
for I := 1 to Pred(trk.Points.Count) do
begin
pt2 := trk.Points[I].RealPoint;
@ -1964,14 +2034,16 @@ begin
iPt4 := (iPt1 - iPt2); // delta to the right point
end;
// Draw all copies of the segment, right to left
repeat
ClipDrawLine(iPt3, iPt3 + iPt4);
iPt3 := CyclicPointOf(iPt3, Pred(iPt3.X), False); // Next left cyclic iPt3
until Max(iPt3.X, iPt3.X + iPt4.X) < ClipRect.Left;
if TSegmentExtraData.MarkOf(trk.Points[Pred(I)].ExtraData) <> smEnd then
// Draw all copies of the segment, right to left
repeat
ClipDrawLine(iPt3, iPt3 + iPt4);
iPt3 := CyclicPointOf(iPt3, Pred(iPt3.X), False); // Next left cyclic iPt3
until Max(iPt3.X, iPt3.X + iPt4.X) < ClipRect.Left;
pt1 := pt2;
iPt1 := iPt2;
EndSegm := TSegmentExtraData.MarkOf(trk.Points[I].ExtraData) = smEnd;
end;
end;