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
This property has a function that allows you to find the closest line to a particular point.
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;
procedure Insert(const index: integer; const Lat, Lng : double; const Alt: double = _ErrorAltitude);
function Add(const dLatLngs: array of double): integer;Unlike adding a simple point, you do need to manage the addition of your table by BeginUpdate / EndUpdate, is done automatically.
1Reverse the direction of the line
property ShowDirection : boolean
Add arrows to each segment to show direction
procedure Slice(ALat,ALng,BLat,BLng:double;Line: TECShapeLine);
If these points are not on the line, they are replaced by the nearest points on the line
If these points are not on the line, they are replaced by the nearest points on the line
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
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;
procedure Delete(index: integer);
property Encoded: string ;
property EncodePrecision: byte;
function Count: integer;
property Weight: byte read FWeight write setWeight;
property BorderSize : integerproperty PenStyle : TPenStyle
Using psUserStyle and setCustomDash([len_dash,len_space,..,len_dashx,len_spacex]) you can create your pattern of traits
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}');
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)
// 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;
property Path[index: integer]: TECPointLine default;
Array containing all the points of the line
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]
1function Distance : 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.
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;
property NorthEastLatitude: double
property NorthEastLongitude: double
property SouthWestLatitude: double
property SouthWestLongitude: double
// Delphi
map component TECNativeMap
line := map.Shapes.Lines[0];
// show the entire
line
map.fitBounds(line.NorthEastLatitude,line.NorthEastLongitude,line.SouthWestLatitude,line.SouthWestLongitude);
property Editable : boolean
property Shapes : TECShapesIf 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;
Editing mode
property Editable : booleanUse 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.
// 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
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.
Use the properties FilenameStartEditLine, FilenameEndEditLine, FilenamePointEditLine of your map to change the bitmaps
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;
property OnShapePathChange : TNotifyEvent
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)
...
SelectLine := TecNativeLineSelect.create;
// triggered by selection
SelectLine.OnSelect := doSelect;
// triggered by deselection
SelectLine.OnDeselect := doDeselect;
SelectLine.Line := your_Line;
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]
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.
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.
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.
PtA,PtB : TECShapeMarker;
...
PtA := map.shapes.Markers[0];
PtB := map.shapes.Markers[1];
line := map.AddGeodesicLine(PtA.Latitude,ptA.Longitude,ptB.Latitude,ptB.Longitude);
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.You first need to get a key to use the api of OpenWeatherMap
// Get the weather along a TECShapeLine
Line.ShowWeather := true;
See the RouteWeather demo for more information on how to use the api of OpenWeatherMap.