Subscribe to this thread
Home - General / All posts - Scripting point along line in M9
vincent

1,683 post(s)
#14-Jun-18 15:27

Hi,

I have the following M8 script to create points at every meter along every lines in a drawing. I would like to know if M9 is able to do that before converting the script. So, is it ?

function Main() {

// javascript

var lignes = Document.ComponentSet.Item("Lignes");

Document.ComponentSet.Item("Points").ObjectSet.RemoveAll();

var queryPoints = Document.ComponentSet.Item("Query_Points");

var i = 0;

var nb_Lignes = lignes.ObjectSet.Count;

var ligne_No = 0;

var dist = 0;

var point_No = "";

var longueur = 0;

var table = lignes.OwnedTable.RecordSet;

for ( i = 0 ; i < nb_Lignes ; i++)

{

ligne_No = table.Item(i).Data("no_ligne");

longueur = table.Item(i).Data("long");

 for ( dist = 0 ; dist <= longueur ; dist++)

 {

 point_No = ligne_No + "_" + dist;

 

 queryPoints.Text = 'Insert Into [Points] ( [Geom (I)], [no_ligne], [no_point] ) Values ((Select LinePoint (GEO ,' + dist + ',"m") from (Select [Geom (I)] As GEO from [Lignes] where ID = '+ ligne_No + ')),'+ligne_No+', "'+point_No+'")';

 queryPoints.Run();

 }

}

}

adamw


7,948 post(s)
#14-Jun-18 16:21

Yes, of course.

You can either use a script, as in 8 (see the API doc, if you have issues figuring out what's what after reading the short set of overviews, ask here), or you can use GeomSegmentize in a query.

vincent

1,683 post(s)
#14-Jun-18 17:31

Segmentize followed by Convert to Points transforms would have been nice, but Segmentize produces segments equal OR LESS than the specified value. I cannot use that.

Anything similar to M8's SQL LinePoint available ?

adamw


7,948 post(s)
#15-Jun-18 15:58

We don't yet have the analog of LinePoint available in SQL. You can create one using a script.

But in general, aren't we always going to have a small segment at the end of each branch? If the end coordinate from that segment is unwanted, it can be filtered based on segment length.

tjhb
8,059 post(s)
#16-Jun-18 04:45

I think the most economical function, whether built-in or custom, would subdivide each branch of each input line (or area boundary) into sections of length L, with a flag to return the last point as well if there is some length left over at the end (for both areas and lines I think).

That would avoid unnecessary function calls (one call per "LinePoint" would be inefficient), bearing in mind that the most frequent use of the function would be to create a series of evenly-spaced points.

Needing just one point is less common, but if necessary that could be a separate function.

I have started sketching a script-function for this. All going well I will come back when it nearly works.

vincent

1,683 post(s)
#18-Jun-18 14:09

Interesting, Tim.

LinePoint is normalizing geometry I guess. Lines are splitted at intersections. I have one branche lines that I don't want to be splitted. To avoid that, I send each line in another drawing with an Insert Into via a script and a query. Then I run LinePoint on the drawing that contains only one line. A loop process all lines, one by one. The output I what I need.

So, this is working. But obviously, I'm looking for more speed, considering the number of lines and points to process.

Using your idea of splitting lines into 1 meter sections and returning the end point might be faster in M9 than my script in M8.

Modified script goes like :

function Main() {

// javascript

var lignes = Document.ComponentSet.Item("Lignes");

var lignesIsol = Document.ComponentSet.Item("Lignes_isolees");

Document.ComponentSet.Item("Points").ObjectSet.RemoveAll();

lignesIsol.ObjectSet.RemoveAll();

var queryPoints = Document.ComponentSet.Item("Query_Points");

var i = 0;

var nb_Lignes = lignes.ObjectSet.Count;

var ligne_No = 0;

var dist = 0;

var point_No = "";

var longueur = 0;

var table = lignes.OwnedTable.RecordSet;

var table2 = lignesIsol.OwnedTable.RecordSet;

var indexL = 0;

//for ( i = 0 ; i < nb_Lignes ; i++)

for ( i = 0 ; i < 4 ; i++)

{

indexL = table.Item(i).Data("ID");

queryPoints.Text = 'Insert Into [Lignes_isolees] Select * from [Lignes] where [ID] = ' + indexL ;

queryPoints.Run();

ligne_No = table2.Item(0).Data("no_ligne");

longueur = table2.Item(0).Data("long");

 for ( dist = 0 ; dist <= longueur ; dist++)

 {

 point_No = ligne_No + "_" + dist;

 queryPoints.Text = 'Insert Into [Points] ( [Geom (I)], [no_ligne], [no_point] ) Values ((Select LinePoint (GEO ,' + dist + ',"m") from (Select [Geom (I)] As GEO from [Lignes_isolees] where [no_ligne] = '+ ligne_No + ')),'+ligne_No+', "'+point_No+'")';

 queryPoints.Run();

 }

lignesIsol.ObjectSet.RemoveAll();

}

}

vincent

1,683 post(s)
#18-Jun-18 15:16

I removed the WHERE clause in the last loop. It was no longer useful. Interesting speed gain.

adamw


7,948 post(s)
#21-Jun-18 16:31

Could you post example MAP file with model data? (Just want to match the input / output exactly.)

vincent

1,683 post(s)
#22-Jun-18 17:14

I built a sequence generator based on one of your old post. Amazingly fast !

--SQL

SELECT 

 

  LinePoint(d.[geom (i)], a.v*1)

 

FROM [Lignes 3] AS d,

(SELECT (a4.v*1000 + a3.v*100 + a1.v*10 + a2.v)  AS v FROM

((VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9) NAMES (v)) AS a1,

 (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9) NAMES (v)) AS a2,

(VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9) NAMES (v))  AS a3,

(VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9) NAMES (v))  AS a4

))

As a

 WHERE d.[length (i)] >= a.v*1

tjhb
8,059 post(s)
#22-Jun-18 18:34

SQL9 has dedicated syntax for that: ValueSequence(). Much more flexible, and completely succinct.

And post some sample data! Adam is offering a full script. I am still working on it too, but am glad if that will be irrelevant now.

Manifold User Community Use Agreement Copyright (C) 2007-2017 Manifold Software Limited. All rights reserved.