Composant Delphi / Google Maps / OpenStreetMap / Leaflet  / Mappilary / Native Maps 100% Delphi 0% WebBrowser 0% Javascript

TECShapeLine

you are here :TECNativeMap > Shapes

TECShapeLine allows you to plot a line consisting of a set of points on your card.

The lines are managed by an TECShapeLines list accessible through the property Lines of the TECShapes groups

Fig. 1 A polyline in edit mode

This property has a function that allows you to find the closest line to a particular point.

var nl : TNearestLine ;
nl := map.shapes.lines.NearestLineToPoint(lat,lng);
/// nl.line is the closest line to lat,lng position
if assigned(nl.line) then
begin
nl.lat; // latitude on line
nl.lng; // longitude on line
nl.distance; // distance to line in meters
end;

TECShapeline

This class descends from TECShape

It additionally has the following properties

function Add(const Lat, Lng: double; const Alt: double = _ErrorAltitude): integer;

Add a point with potentially altitude

procedure Insert(const index: integer; const Lat, Lng : double; const Alt: double = _ErrorAltitude);

function Add(const dLatLngs: array of double): integer;
Adds an array of points, consisting of a suite of latitudes and longitudes
line.add([lat1,lng1,lat2,lng2,...,latx,lngx]);

Unlike adding a simple point, you do need to manage the addition of your table by BeginUpdate / EndUpdate, is done automatically.

1
Inserts a point with potentially altitude
procedure Reverse
Reverse the direction of the line

property ShowDirection : boolean
Add arrows to each segment to show direction

Fig. 2 ShowDirection

procedure Slice(ALat,ALng,BLat,BLng:double;Line: TECShapeLine);
Copy the part bounded by the geographical coordinates into Line
If these points are not on the line, they are replaced by the nearest points on the line
function Slice(ALat,ALng,BLat,BLng:double;GroupName: string = ''): TECShapeLine;
Returns a line composed of the portion bounded by the geographical coordinates
If these points are not on the line, they are replaced by the nearest points on the line
procedure Slice(const StartIndex,EndIndex : integer;Line : TECShapeLine); overload;
Copy the part bounded by the StartIndex and EndIndex segments in Line

function Slice(const StartIndex,EndIndex:integer;GroupName:string=''):TECShapeLine; overload;
Returns a line composed of the portion bounded by the StartIndex and EndIndex segments

procedure Slice(const StartKm,EndKm : double;Line : TECShapeLine); overload;
Copy the part starting at the StartKM kilometre and ending at the EndKM kilometre in Line

function Slice(const StartKm,EndKm : double;GroupName:string=''):TECShapeLine; overload;
Returns a line consisting of the portion commencing at kilometre StartKM and ending at the EndKM kilometre

Fig. 3 slice - red color between 1.2 km and 3.8 kilometer

var redLine:TECShapeLine;

if map.shapes.lines.count>0 then
begin
redLine := map.shapes.lines[0].slice(1.2,3.8);
redLine.color := clRed;
end;

// also
map['group_name'].lines.count> 0 then
map['group_name'].lines[0].slice(1.2,3.8).color := clRed;

procedure Clear;

Clears the points

procedure Delete(index: integer);

property Encoded: string ;

Encode / Decode the polyline by using the algorithm of google ( developers.google.com/maps/documentation/utilities/polylinealgorithm )

property EncodePrecision: byte;

Accuracy of encoding, default 5 decimal places (180.00000 to -180.00000)
Removes a segment of the line

function Count: integer;

Indicates the number of segment

property Weight: byte read FWeight write setWeight;

property BorderSize : integer
Border thickness
property BorderColor : TColor
Color of the border
property HoverBorderColor : TColor
Border color when the mouse hovers over it

Fig. 4 2 pixel black border

Line thickness

property PenStyle : TPenStyle

stroke type psSolid, psDash, psDot , psDashDot and psUserStyle are available

Using psUserStyle and setCustomDash([len_dash,len_space,..,len_dashx,len_spacex]) you can create your pattern of traits

line.penStyle := psUserStyle;
line.SetCustomDash([4,4,2,4,4,4]);
//you can use in styles like this
map.styles.addRule('#_DRAGZOOM_.line {weight:4;color:green;penStyle:userStyle;customStyle:4,4,2,4,4,4}');

You can animate the traits

property LineType : TECLineType

ltStraight Connect points without displaying them (default)

ltBezier Draw bezier curves between points

ltDot Display points without connecting them

ltDotLine Display points and link them together (equivalent to ltDot + ltStraight)

Fig. 5 Penstyle := psDashDot - LineType := ltBezier

procedure getAltitudes(Event: TOnGetAltitude = nil);
Calculates the altitudes of the points, you can pass a procedure of type TOnGetAltitude to display a progress bar (see DemoNativeRoute)

// Delphi map component ECMap

// calcul altitude for all point of polyline 0
// you can pass nil if you don't show a progressbar
map.Shapes.Lines[0].GetAltitudes(doGetAltitude);
...
{*
event fired by getAltitudes

@param Sender TECShapeLine
@param Total number of altitude's point calculated
@cancel flag for abort calcul
}
procedure TFDemoRoute.doOnGetAltitude(Sender: TECShapeLine;const Total:integer;var cancel:boolean);
begin
ProgressAltitude.Position := total;
// cancel if press button
cancel := btAbortAlt.tag = -1;
end;

function getLatLngFromMeter(const SensStartEnd: boolean;
const lMeter: longint; var dLatitude, dLongitude: double;
var idPoint: integer; var Heading: integer; var bEnd: boolean): boolean;

Calculates the latitude and longitude of a point on the line/polygon based on its distance in metres, returns True if a point was found

SensStartEnd meaning of the course, true for departure -> arrival

lMeter the distance in metres

dLatitude,dLongitude variables of type double who will receive the latitude and longitude

idPoint a variable that will contain the index in the array Path where is located the point, the calculation returns an approximation because your polyline/polygon has all of the actual points

Heading a variable that will contain the angle of the point relative to the North (from 0 to 360 °)

bEnd indicates whether one has reached or exceeded the end of polyline/polygone(or early depending on the direction)

property HoverPoint: integer read FHOverSeg;

Index of the segment pointed by the mouse

property Path[index: integer]: TECPointLine default;


Array containing all the points of the line

TECPointLine = class
public
property Latitude: double ;
property Longitude: double ;
property Alt: double ;
property Distance: integer ; // meters
property Text: string ;
property Time: TDateTime ;
property Maneuver: string ;
property item: TObject ;
end;

You can access it directly with line[index] instead of line.Path[index]

1
property PathIndexChange: integer
Indicates the index of the point that has been added, deleted or moved.
property PathChange : TPathChange
Indicates the type of change: pcDelete, pcAdd or pcMove

function Distance : double;

Indicates the total distance (km) of the line
function DistanceBetweenIndexPoint(const idxA,idxB: integer): double;
Returns the distance in km between 2 points of the line
function DistanceBetween(const ALat,ALng,BLat,BLng:double): double ;

Returns the distance in km between 2 geographical points located on the line.

If the points are not on the line, they are replaced by the 2 nearest points on the line.

function DistanceToPoint(const ALat,ALng:double): double ;

Returns the distance in km from start to geographical point located on the line.

If the point is not on the line, it is replaced by the nearest point on the line.

property Duration : integer;

If the row represents a route (route) indicates the duration of the trip.

property NorthEastLatitude: double

Latitude of the upper right corner of the box enclosing the line

property NorthEastLongitude: double

Longitude of the upper-right corner of the box enclosing the line

property SouthWestLatitude: double

Latitude of the lower left corner of the box enclosing the line

property SouthWestLongitude: double

Longitude Latitude from the lower left of the box enclosing the line

// Delphi map component TECNativeMap

line := map.Shapes.Lines[0];

// show the entire line
map.fitBounds(line.NorthEastLatitude,line.NorthEastLongitude,line.SouthWestLatitude,line.SouthWestLongitude);

property ShowText : boolean
If the row represents a road displays the intermediate points

property Editable : boolean

property Shapes : TECShapes

If the row represents a road provides access to the forms that indicate the steps

The departure and arrival points are represented by TECShapePOI, the other intermediate points are TECShapeMarker

The example below enables to change the display of the points of departure and arrival.

// Delphi map component TECNativeMap
// change default poi start and finish of route
var line : TECShapeLine;
...
line := map.shapes.lines[0];

if line.shapes.Pois.count>1 then
begin
i := line.shapes.markers.add(line.shapes.pois[0].latitude,line.shapes.pois[ 0].longitude);
line.shapes.markers[i].filename := 'http://www.helpandweb.com/flag_blue.png';
line.shapes.markers[i].hint := line.shapes.pois[0].hint;

i := line.shapes.markers.add(line.shapes.pois[line.shapes.Pois.count- 1].latitude,line.shapes.pois[line.shapes.Pois.count- 1].longitude);
line.shapes.markers[i].XAnchor := 0;
line.shapes.markers[i].filename := 'http://www.helpandweb.com/checkered_flag.png';

line.shapes.markers[i].hint := line.shapes.pois[line.shapes.Pois.count-1].hint;

// hide default start and finish
line.shapes.pois[0].visible := false;
line.shapes.pois[line.shapes.Pois.count-1].visible := false;
end;

Fig. 6 Adding flags for the departure and arrival

Editing mode

property Editable : boolean
Makes the line or polygon editable, a long click on a point removes it, a double click on a segment adds a point, the element can be moved with the mouse, right click on the last point to exit the editing mode.

Use the EditShadowLine property of your map to hide or modify the trace of the future line.
The map also has a EditShape property of type TECShape that contains the element being edited.

2

Fig. 7 Lines & Polygones editable

...
// hide shadow line
Map.EditShadowLine.visible := false;
// you can also use style for this line
Map.Styles.addRule('#_EDIT_SHADOW_LINE_ {color:red;penStyle:dot}');

// Add or Edit a line when clicking on the map
procedure TForm.MapClick(sender: TObject; const Lat, Lng: Double);
var Line : TECShapeLine;
begin

if (map.editshape is TECShapeLine) then
// if a line is already in edition mode it is used
Line := TECShapeLine(map.editshape)
else
// otherwise we create a new line and put it in edit mode
begin
line := map.addLine;
line.OnShapePathChange := OnPathChangeLine;
line.OnDblClickEditLine := DblClickEditLine;
line.OnChangeEditable := OnEditableLine;
line.editable := true;
end;

// add new point
line.Add(lat,lng);


end;

// triggered when adding, deleting or moving a point in the line
procedure Tform.OnPathChangeLine(Sender: TObject);
var
line : TECShapeLine;
begin

line := TECShapeLine(Sender);

// Use PathChange to find out the type of change
// Use PathIndexChange to determine the index of the modified point

case line.PathChange of
pcDelete: caption := 'delete' ;
pcAdd: caption := 'add';
pcMove: caption := 'move' ;
end;

end;

// Triggered by a double click on the line in edit mode
procedure TForm.OnDblClickEditLine(sender: TECShape; const IndexPoint: integer;
const NewLat, NewLng: double; var cancel: boolean);
begin

// do not delete the first and the last points
if (TECShapeLine(sender).PathChange=pcDelete) then
cancel := (IndexPoint=0) or (IndexPoint=TECShapeLine(sender).count-1);

end;

// Triggered when changing the editable mode
procedure TForm.OnEditableLine(sender:TObject);
begin

if TECShapeLine(sender).editable then
showmessage('start edit')
else
showmessage('end edit');
end;

This allows that straight paths, to modify a route it takes just 2-3 lines of additional code.
You can also make a freehand draw

1

By default the selection points are represented by a black square to the starting point, a white square to the end point and a white circle for the intermediate points.

Fig. 8 Edit line

Use the properties FilenameStartEditLine, FilenameEndEditLine, FilenamePointEditLine of your map to change the bitmaps

// Reverse the point of departure and arrival
s := map.FilenameStartEditLine;
map.FilenameStartEditLine := map.FilenameEndEditLine;
map.FilenameEndEditLine := s;

You can change the creation of the selection points using the property OnCreateShapeLinePoint

line := map.add(nsLine,Lat,Lng);

// change défault point
line.OnCreateShapeLinePoint := doCreateShapeLinePointEditable;


procedure TForm1.doCreateShapeLinePointEditable(sender: TObject; const Group:TECShapes;
var ShapeLinePoint: TECShape;
const Lat,Lng:double;const index:integer);
var i:integer;
poi:TECShapePOI;
begin

i := Group.Pois.add(lat,Lng);
Poi := Group.Pois[i];

ShapeLinePoint := poi;

poi.Width := 10;
poi.Height:= 10;

poi.POIShape := poiRect;

poi.Color := claWhite;
poi.HoverColor := claWhite;
poi.BorderColor := claBlack;
poi.HoverBorderColor:= claBlack;

end;


Fig. 9 Changing the appearance of a TECShapeLine points

property OnShapePathChange : TNotifyEvent

To be informed when the line changes.

Select a portion of the line

To select a portion of your line with the mouse or by code, use the TecNativeLineSelect class (unit uecEditNativeLine)

var SelectLine : TecNativeLineSelect;
...
SelectLine := TecNativeLineSelect.create;
// triggered by selection
SelectLine.OnSelect := doSelect;
// triggered by deselection
SelectLine.OnDeselect := doDeselect;

SelectLine.Line := your_Line;

Fig. 10 Selection of a part of a line or polygon

Hover over the line and click on the selection point to validate it, click on it again to remove it, the OnSelect event is triggered as soon as the validation of the second point

You can then create a line or a polygon with SelectionTo, or go directly to the selected with points Selection[x]

// triggered by selection
procedure form.doSelect(Sender: TObject);
begin

// convert selected points to a new line
if not assigned(NewLine) then
newLine := map.addLine(0,0);

SelectLine.SelectionTo(newLine);


// convert selected points to a new polygone
if not assigned(NewPoly) then
newPoly := map.addPolygone(0,0);

SelectLine.SelectionTo(newPoly);

end;


end;

Use SelectionFrom(ALat,ALng,BLat,BLng) for the code segment selection.

// select portion by code
SelectLine.SelectionFrom(Alat,ALng,BLat,BLng);

// returns the distance (double) of the selection in km
d := SelectionDistance;

// return number of points in selection
SelectLine.Count;

// return point (TECPointLine) number x in selection
P := SelectLine.Selection[x];

// deselect portion by code
SelectLine.Deselect;

Geodesic line

A geodesic is the shortest path between two point, use the AddGeodesicLine function to create a.

function TNativeMapControl.AddGeodesicLine(const SLat,SLng,ELat,ELng:double;
const GroupName: string = '';
const maxSegmentLength:integer=5000): TECShapeLine;

You need at least to indicate the coordinates of two points.

maxSegmentLength set the maximum size, in meters, intermediate segments.

var line:TECshapeLine;
PtA,PtB : TECShapeMarker;
...

PtA := map.shapes.Markers[0];
PtB := map.shapes.Markers[1];
line := map.AddGeodesicLine(PtA.Latitude,ptA.Longitude,ptB.Latitude,ptB.Longitude);

Fig. 11 geodesic line

Save moving

The purpose of this example is to save its movement in a TECShapeLine, a triangle pointing in the direction of the displacement will indicate the current position.

var MyLocationShape : TECShapePOI;
MyLocationLine : TECShapeLine;

procedure TForm1.FormCreate;
begin
// create triangle
MyLocationShape := map.AddPoi(0, 0);
MyLocationShape.POIShape := poiTriangle;
MyLocationShape.Width := 18;
MyLocationShape.height := 24;
MyLocationShape.YAnchor := 0 ;
MyLocationShape.visible := false;
end;

// Connect this to your TLocationSensor.OnLocationChanged
// save your location in a TECShapeLine
procedure TForm1.LocationSensorLocationChanged(Sender: TObject;
const OldLocation, NewLocation: TLocationCoord2D);

begin

map.beginupdate;

// create new line if not assigned
if not assigned(MyLocationLine) then
begin
MyLocationLine := map.AddLine(NewLocation.Latitude, NewLocation.Longitude,
'mylocations');
MyLocationLine.weight := 4;
MyLocationLine.Color := GetRandomColor;

// add border
MyLocationLine.BorderSize := 2;
MyLocationLine.BorderColor := GetShadowColorBy(MyLocationLine.Color, 32);

end

else

MyLocationLine.add(NewLocation.Latitude, NewLocation.Longitude);


MyLocationShape.SetDirection(NewLocation.Latitude, NewLocation.Longitude);

MyLocationShape.visible := true;

// center on your position
map.setCenter(NewLocation.Latitude, NewLocation.Longitude);

map.endupdate;

end;

Weather

By using the services of OpenWeatherMap.org you can view the weather along your TECShapeLine.

Fig. 12 Weather on the road

You first need to get a key to use the api of OpenWeatherMap

map.OpenWeather.Key := your_key;

// Get the weather along a TECShapeLine
Line.ShowWeather := true;

See the RouteWeather demo for more information on how to use the api of OpenWeatherMap.

go to page
Réalisé avec la version gratuite pour les particuliers d'Help&Web