API#

startinpy does not have specific classes and/or objects for points, vertices, and triangles. NumPy arrays of floats and integers are used.

A Point is an array of 3 floats (x-coordinate, y-coordinate, z-coordinate):

>>> import startinpy
>>> dt = startinpy.DT()
>>> dt.insert_one_pt(11.3, 22.2, 4.7)
>>> dt.points[1]
array([11.3, 22.2, 4.7])

A Vertex is an integer, it is the index in the array of points (startinpy.DT.points(), which is 0-based).

A Triangle is an array of 3 integers, the values of the indices of the 3 vertices (ordered counter-clockwise) in the array of points (startinpy.DT.points(), which is 0-based).

>>> dt.triangles[2]
array([1, 3, 2], dtype=uint64)
>>> #-- z-coordinate of 3rd vertex of the same triangle
>>> dt.points[dt.triangles[2][2]][2]
3.3

Important

The first vertex in the list of points is the infinite vertex, and has “infinity” coordinates (it has this: [inf, inf, inf]). It is used internally to ensure that the whole DT is consistent. No finite Triangle refers to the vertex. See more info and some examples.

class startinpy.DT#

A Delaunay triangulation (DT), containing vertices+triangles

adjacent_triangles_to_triangle()#

Return the triangles adjacent to Triangle t. Exception thrown if vertex index doesn’t exist in the DT.

Parameters:

vi – the vertex index

Returns:

an array of 3 triangles (finite and infinite)

>>> tris = dt.adjacent_triangles_to_triangle([1, 44, 23])
>>> for i, t in enumerate(tris):
>>>     print(i, t)    
0 [3 4 6]
1 [3 6 7]
2 [3 7 8]
adjacent_vertices_to_vertex()#

Return an array of vertex indices that are adjacent to vertex vi, that is those on the edges incident to vi. An exception is thrown if vi does not exist in the DT.

Parameters:

vi – the vertex index

Returns:

an array of vertex indices (ordered counter-clockwise)

closest_point()#

Return the closest vertex index to [x, y] (distance in 2D). An Exception is thrown if [x, y] is outside the convex hull.

Parameters:
  • x – the x-coordinate

  • y – the y-coordinate

Returns:

the vertex index of the closest point

>>> try:
>>>     cp = dt.closest_point(32.1, 66.9)
>>> except Exception as e:
>>>     print(e)
collect_garbage()#

Collect garbage, that is remove from memory (the array dt.points) the vertices marked as removed.

Watch out: the vertices get new IDs, and thus the triangles get updated too. And this can be a slow operation.

>>> if dt.has_garbage():
>>>     dt.collect_garbage()
>>> assert (dt.has_garbage() == False)
convex_hull()#

Return the convex hull as an array of vertex indices.

Returns:

an array of vertex indices, oriented counter-clockwise (CCW)

>>> dt.convex_hull()
array([2, 13, 4, 51, 27], dtype=uint64)
get_bbox()#

Return the bbox of the dataset

Returns:

an array of 4 coordinates: [minx, miny, maxx, maxy]

>>> bbox = dt.get_bbox()
array([ 0., 0., 10., 12. ])
get_point()#

Return the point for the vertex with index vi. An exception is thrown if vertex index is invalid.

Parameters:

vi – the index of the vertex

Returns:

the point

>>> v = dt.get_point(4)
array([13., 2.0, 11.])
has_garbage()#

Returns true if some vertices are marked as to be deleted (but still in memory) , false otherwise.

Returns:

true/false

incident_triangles_to_vertex()#

Return the triangles incident to vertex vi. Infinite triangles are also returned. Exception thrown if vertex index doesn’t exist in the DT or if it has been removed.

Parameters:

vi – the vertex index

Returns:

an array of triangles (ordered counter-clockwise)

>>> trs = dt.incident_triangles_to_vertex(3)
>>> for i, t in enumerate(trs):
>>>     print(i, t)    
0 [3 4 6]
1 [3 6 7]
2 [3 7 8]
3 [3 8 2]
4 [3 2 9]
5 [3 9 4]
insert(pts, *, insertionstrategy='AsIs')#

Insert each point in the array of points (a 2D array) by calling insert_one_pt() for each. Different insertion strategies can be used: “AsIs” (default: inserts points in the order given) or “BBox” (inserts first the BBox of the points, which speeds up the construction, works especially good for rasters).

Parameters:
  • pts – an array of points (which is an array)

  • insertionstrategy (optional) – “AsIs” (default) or “BBox”

Returns:

(nothing)

>>> pts = []
>>> pts.append([1.0, 1.0, 11.11])
>>> pts.append([1.0, 2.3, 22.22])
>>> pts.append([12.3, 21.0, 4.52])
>>> ...
>>> dt = startinpy.DT()
>>> dt.insert(pts)
OR
>>> dt.insert(pts, insertionstrategy="BBox")
insert_one_pt()#

Insert one new point in the DT.

If there is a point at the same location (based on startinpy.DT.snap_tolerance()), then the point is not inserted and the index of the already existing vertex is returned.

Parameters:
  • x – x-coordinate of point to insert

  • y – y-coordinate of point to insert

  • z – z-coordinate of point to insert

Returns:

index of the vertex in the DT

>>> dt.insert_one_pt(3.2, 1.1, 17.0)
5
(the vertex index in the DT is 5)
interpolate()#

Interpolate with 5 different methods:

  1. IDW: inverse distance weighing

  2. Laplace: a faster NNI with almost the same results

  3. NN: nearest neighbour

  4. NNI: natural neighbour interpolation

  5. TIN: linear interpolation in TIN

Parameters:
  • interpolant – a JSON/dict Python object with a “method”: “IDW” (or others). IDW has 2 more params: “power” and “radius”

  • locations – an array of [x, y] locations where to interpolate

  • strict – if the interpolation cannot find a value (because outside convex hull or search radius too small) then strict==True will stop at the first error and return that error. If strict==False then numpy.nan is returned.

Returns:

a numpy array containing all the interpolation values (same order as input array)

>>> locs = [ [50.0, 41.1], [101.1, 33.2], [80.0, 66.0] ]
>>> re = dt.interpolate({"method": "NNI"}, locs)
>>> re = dt.interpolate({"method": "IDW", "radius": 20, "power": 2.0}, locs, strict=True)
is_finite()#

Verify whether a Triangle is finite, or not. An infinite triangle has the first 0-vertex as one of its vertices. This doesn’t verify wether the triangle exists (use is_valid()).

Parameters:

t – the triangle, an array of 3 vertex indices

Returns:

True if t is finite, False is infinite

>>> re = dt.is_finite(np.array([11, 162, 666])))
is_inside_convex_hull()#

Is the point [x, y] located inside the convex hull of the DT.

Parameters:
  • x – the x-coordinate

  • y – the y-coordinate

Returns:

True if [x,y] is inside the convex hull or on its boundary, False otherwise.

is_triangle()#

Verify if a triangle exists in the DT.

Parameters:

t – the triangle, an array of 3 vertex indices

Returns:

True if t exists, False otherwise

>>> dt.is_triangle(np.array([11, 162, 66]))
False
is_vertex_convex_hull()#

Return True if vertex vi is on the boundary of the convex hull, False otherwise.

Parameters:

vi – the vertex index

Returns:

True if vi is on the boundary of the convex hull, False otherwise. Also False is returned if the vertex doesn’t exist in the DT.

is_vertex_removed()#

Return True if vertex vi is labelled as removed, False otherwise.

Parameters:

vi – the vertex index

Returns:

True if vi is labelled as removed, False otherwise. An exception is raised if vi doesn’t exist.

locate()#

Locate the triangle containing the point [x, y] (projected to 2D). An error is thrown if it is outside the convex hull.

Parameters:
  • x – the x-coordinate

  • y – the y-coordinate

Returns:

the triangle

number_of_triangles()#
Returns:

number of finite triangles

number_of_vertices()#
Returns:

number of finite vertices

points#

Get the points [x, y, z] of all vertices in the DT. This includes the infinite vertex (vertex at position 0), which is not part of the DT (no finite Triangle reference it, but infinite Triangles do)

>>> pts = dt.points
>>> print(pts.shape) #-- this is a numpy array
(102, 3)
>>> for p in pts:
>>>     print(p[0], p[1], p[2])
...
>>> dt.points[27]
array([101.122, 72.293, 11.223])
>>> dt.points[0]
array([inf, inf, inf])
read_las(path, *, classification=None, thinning=1)#

Read the LAS/LAZ file and insert all the points in the DT.

Parameters:
  • path – full path (a string) on disk of the file to read

  • classification (optional) – a list of class(es) to keep. If not used then all points are inserted.

  • thinning (optional) – the thinning factor, eg 10 will randomly pick 1/10 points from the file.

Returns:

throws an exception if the path is invalid

>>> dt = startinpy.DT()
>>> dt.read_las("/home/elvis/myfile.laz")
>>> OR
>>> dt.read_las("/home/elvis/myfile.laz", classification=[2,6])
>>> OR
>>> dt.read_las("/home/elvis/myfile.laz", thinning=10, classification=[2,6])
remove()#

Remove/delete the vertex vi (an index) from the DT, and update the DT for the Delaunay criterion.

Parameters:

vi – index of vertex to delete

Returns:

(Exception is thrown if vi is invalid)

>>> try:
>>>     t.remove(45)
>>> except Exception as e:
>>>     print(e)
snap_tolerance#

Get/set the snap tolerance used to merge vertices during insertion. Two vertices closer than this will be the merged during insertion. (default=0.001)

>>> dt = startinpy.DT()
>>> dt.snap_tolerance = 0.05 #-- modify to 0.05unit
>>> print("The snap tolerance is:", dt.snap_tolerance)
The snap tolerance is: 0.05
triangles#

Get the triangles in the DT.

>>> trs = dt.triangles
>>> print(trs.shape)
(224, 3) #-- this is a numpy array
>>> one_triangle = trs[22]
>>> first_vertex = one_triangle[0]
>>> print("x-coordinate of first vertex: ", dt.points[first_vertex])
x-coordinate of first vertex: [25.98 35.12 4.78]
vertical_exaggeration()#

Vertically exaggerate the elevation values of the vertices. Used mostly for visualisation.

Parameters:

factor – a positive value (can be <1.0 to remove exaggeration)

Returns:

(nothing)

>>> dt.vertical_exaggeration(2.0)
>>> dt.vertical_exaggeration(0.5)
write_cityjson()#

Write a CityJSON file of the DT (vertices+triangles) to the path (a string). One TINRelief object is created. Throws an exception if the path is invalid.

Parameters:
  • path – full path (a string) on disk of the file to create (will overwrite)

  • digits – (default=3) number of digits to keep (for saving efficiently the coordinates)

Returns:

(nothing)

>>> dt.write_cityjson("/home/elvis/myfile.city.json")
write_geojson()#

Write a GeoJSON file of the DT (vertices+triangles) to the path (a string). Throws an exception if the path is invalid.

Parameters:

path – full path (a string) on disk of the file to create (will overwrite)

Returns:

(nothing)

>>> dt.write_geojson("/home/elvis/myfile.geojson")
write_obj()#

Write an OBJ of the DT to the path (a string). Throws an exception if the path is invalid.

Parameters:

path – full path (a string) on disk of the file to create (will overwrite)

Returns:

(nothing)

>>> dt.write_obj("/home/elvis/myfile.obj")
write_ply()#

Write an PLY of the DT to the path (a string). Throws an exception if the path is invalid.

Parameters:

path – full path (a string) on disk of the file to create (will overwrite)

Returns:

(nothing)

>>> dt.write_ply("/home/elvis/myfile.ply")