Geometry overview
In reports, geometries are used to construct spatial queries such as finding all the trees within a 10m of a span.
In order to run network reports and export geo data such as GeoJSON and shapefiles, the schema needs a specified geometry field. This geometry field associates a report row (including the object and it's report fields) to a geographical location. Most schemas have a built-in geometry field.
In other cases, you can specify a custom geometry field
Geometry types
In Neara, there are two types of geometries. The most common one is Coordinate Distance Geometry which corresponds to GeoJSON geometries:
Point
Linestring
Polygon
The coordinates for these types are not exposed. As a result, these types are not directly modifiable or manipulatable. Instead, vector arithmetic can be performed by constructing vectors using vec2
, vec3
.
vec2(x,y)
- vector in 2D spacevec3(x,y,z)
- vector in 3D spaceget_centroid(geometry)
- returns the centroid of the geometry Vec2<Co-ord dist>
Vector functions
normalize(vec)
Returns a vector with the same direction as the specified vector and a magnitude of 1.
geoJSON
Vectors can be turned into geoJSON with these functions:
geo_point()
- convertsvec2/vec3
intoPoint
geo_linestring()
- converts two or morevec2/vec3
intoLinestring
orMulti Linestring
geo_polygon()
- converts three or morevec2/vec3
intoPolygon
orMulti Polygon
New geometries
New geometries can be created using these functions:
make_grid()
- makes a gridmake_outline()
- makes an outline polygon
Spatial and measurement queries
The following functions let you use geometries to do spatial and other measurement queries.
measure_distance()
- finds the closest points between the two objectsgeo_query()
- queries a collection of geometric objects returning those that are within some distance of the given geometry, in order of closest to furthestgeo_intersect()
- returns true if geom1 and geom2 intersect/overlapconvex_area()
- returns the area of the convex hull of the given geometry
Catenaries
Catenaries are another type of geometries exposed in Neara. You can manipulate them using:
extend_catenary()
slice_catenaries()
Body functions
Body functions are used for more complex geometries such as 3D meshes specified in OBJ file formats.
To upload your KML, DXF or OBJ file into Neara, click the (+) button at the right hand end of the tabs in any section of the workspace, and select Data File under the Tools section in the popup.
Once you have imported your file, a Body can be created with the function load_bodies()
. The required argument is the Data File that should be parsed. Other optional arguments are available for further customisation. See in-app documentation for more information.
To position the Body within your network, use transform_body()
. This function takes in the loaded bodies, and returns a copy that has been translated and rotated according to the specified arguments.
Bodies can be visualised and used to as inputs to perform measurement calculations.
load_bodies
load_bodies(source, [namedArg:partition_layers, namedArg:terrain_wrap_height, namedArg:map_layers, namedArg: only_layers, namedArg:include_relative_geometries, namedArg:cull_backface])
The function returns a list of Body objects, derived from the source using the provided parameters. The source is either a (DXF or KML) data file or a blob ref.
partition_layers
defaults totrue
. When set tofalse
, all bodies will be merged into a single body with an empty layer name.terrain_wrap_height
determines the offset that is given to 2D primitives relative to the terrain. It will be set to0
by default.only_layers
takes a list of layers, allowing them to be selectively included. When this is not specified all layers will be included.map_layers
takes a map, with keys and values both being strings, allowing layer names to be renamed before partitioning and filtering occurs. By default layer names will be unchanged.terrain_wrap_increment
specifies the maximum distance between adjacent vertices of 2D geometries, before additional vertices are inserted. If a value smaller than 3m is provided it will be interpreted as 3m.extrude_geometry
specifies how much vertical extrusion, generating an extruded skirt, instead of a flat polygonal bodyinclude_relative_geometries
specifies if relative height (2.5D) geometries should be included. If this is set to false, 2.5D geometries will be ignored. This is set to true by default.cull_backface
(advanced) defaults to a "smart" value, set to true or false to enable or disable "back face culling"
There exists a hard limit on the size of each body, being 65,536 unique vertices. If any of the constructed bodies exceeds this limit, no bodies will be created.
make_radial_body
make_radial_body(catenary_likes, [radius, radial_divisions, radial_increment, curve_increment_multiplier, color])
Makes an uncapped radial body around the given cables or catenaries
radius
- the radius of the body around each curveradial_divisions
- the number of sides to the extruded regular polygonradial_increment
- arc length increment for the polygon (specify instead of radial_divisions)curve_increment_multiplier
- (advanced, defaults to 1.0). Change the increment along the curve for polygon ringscolor - a string: an rgb hex color code to shade the body, without the
#
prefix. You can also use an rgb-alpha (RRGGBBAA) hex color code to create a translucent colored body.
transform_body
transform_body(body, [namedArg:translation, namedArg:localX, namedArg:localY, namedArg: localZ])
Returns a copy of the body, with its geometry transformed according to the provided arguments.
The translation argument provides the ability to shift the body by any arbitrary amount. This will default to no translation if not specified.
The localX
, localY
and localZ
arguments perform a change of basis before the translation is applied, allowing any transform to be applied.
For convenience, logical defaults are selected when only a subset of the three vectors are specified. This includes:
When only
localX
/localY
is provided, the remaining two vectors are set such that the transform is a rotation about the vertical (z) axis.When only
localZ
is provided, the remaining two vectors are set such that the transform is a rotation about the X axis.If the above is not applied,
localX
will default tovec3(1.0, 0.0, 0.0)
if not specified,localY
will default tovec3(0.0, 1.0, 0.0)
if not specified, andlocalZ
will default tovec3(0.0, 0.0, 1.0)
if not specified.
Examples
Rotate 180 degrees about the Z axis
transform_body(body, localX: vec3(-1.0m, 0.0, 0.0))
Scale by 2
transform_body(localX: vec3(2.0m, 0.0, 0.0), localY: vec3(0.0m, 2.0m, 0.0), localZ: vec3(0.0, 0.0, 2.0m))
Align with assembly
transform_body(body, localX: normalize(vec3(longitudinal_direction.x, longitudinal_direction.y, 0.0m)), localY: normalize(vec3(longitudinal_direction.y, -longitudinal_direction.x, 0.0m)), localZ: vec3(0.0, 0.0, 1.0), translation: vec3(self.pole.location, self.pole.top_z))
Add a mesh on a pole
Upload a Data File with the name “test.obj”
.
In a custom field on the Model, add the following function:
u_body = load_bodies(find(DataFiles, DataFiles[].name = "test.obj")
To shift the mesh to the top of the pole, we add the following custom field on the Pole:
transform_body(model().u_body, translation: vec3(location,top_z))
Function reference
vec2
vec2(x, y)
or
vec2(vec3)
Generates a 2D vector, given compatible-dimension components or a 3D vector. If built from a 3D vector it drops the Z component. The vector can have dimensional units and participates in dimensional analysis, much like scalars.
Example 1: 2D distance
vec2(3m, 4m)
vec2(3, 4) * 1m
Example 2: Absolute position
vec2(origin()) + vec2(200000m, 600000m)
vec3
vec3(x, y, z)
or
vec3(vec2, z)
Generates a 3D vector, given compatible-dimension components. A 2D vector can be substituted for x and y.
Example 1: 3D distance
vec3(3m, 4m, 5m)
vec3(3, 4, 5) * 1m
Example 2: Absolute position
origin() + vec3(200000m, 600000m, 40m)
normalize
normalize(vector)
Returns the normalized vector (dimensionless, length 1) unless the input is a zero vector in which case a zero vector is returned.
polyline3
polyline3(v1, v2, ...)
or
polyline3(list(v1, v2, ...))
Generates a 3D polyline. All the components must have absolute-coordinate dimensionality.
measure_distance
measure_distance(a, b)
Finds the closest points between the two objects and returns a distance measurement object.
The distance measurement object can be queried for a number of distance components and visualized.
If either a or b are lists, then returns the closest distance between anything in a to anything in b.
Example:
In a custom field on a Span, measure_distance(pole1, pole2)
returns a distance measurement object between the two pole(s) of a span.
The distance object then has a number of useful fields, such as:
start
,end
which are the pair of closest points,distance
which returns the actual distance value,horizontal_distance
andvertical_distance
which return the horizontal and vertical components of that distance,
Note that these last two are NOT necessarily the smallest such values, i.e. horizontal_distance
is the horizontal component of the closest 3D distance, it is not the closest possible horizontal distance.
make_outline
make_outline(geometries, [concavity_radius: 20m, buffer: 10m])
Constructs an outline of the given geometries with buffer.
geometries
: the geometry to outline.concavity_radius
: the inverse of the alpha parameter to an alpha shape routine.buffer
: extra points are automatically added to give thickness to lines and fill in long edges
extend_catenary
extend_catenary(catenary, location)
Extends the given catenary outwards from the closest endpoint so that it reaches the specified 2D location.
reproject
reproject(coord_data, [from_srid: srid, to_srid: srid])
Reprojects data between spatial references.
from
: defaults to the current model sridto
: defaults to lng/lat
Example 1: Reproject a pole to WGS84 using implicit "from" SRID: reproject(pole.location, to: "4326")
Example 2: Reproject a pole to WGS84 using explicit "from" SRID: reproject(pole.location, from: model().srid, to: "4326")
make_grid
make_grid(cell_size: 500m, cover_model: true|false, cover_point_cloud: true|false)
Returns a grid of square polygons of the given size (world-aligned). Specify cover_model
or cover_point_cloud
to select the grid size.
Example:
Create a 100m world-aligned grid ensuring that every model object and every point is covered by a grid cell: make_grid(cell_size: 100m, cover_model: true, cover_point_cloud: true)
geo_linestring
geo_linestring(item1, item2, ...)
Creates a line string or multi line string, each item should be a list(vec2)
or list(vec3)
.
Example 1: Create a LineString geometry on a Span:
geo_linestring(list(pole1.location, pole2.location))
Example 2: Create a MultiLineString on a StrainSection:
geo_linestring( list(index(Spans, 0).pole1.location, index(Spans, 0).pole2.location), list(index(Spans, 1).pole1.location, index(Spans, 1).pole2.location), )
Example 3: Create a LineString geometry directly:
geo_linestring(list( vec2(origin()) + vec2(200000m, 600000m), vec2(origin()) + vec2(200050m, 600000m), vec2(origin()) + vec2(200100m, 600000m), ))
Example 4: Create a MultiLineString geometry directly:
geo_linestring( list(vec2(origin()) + vec2(200000m, 600000m), vec2(origin()) + vec2(200000m, 600001m)), list(vec2(origin()) + vec2(200000m, 600000m), vec2(origin()) + vec2(200000m, 600000m)), )
geo_polygon
geo_polygon(item1, item2, ...)
Creates a polygon or multi polygon, each item is one polygon and should be a list(list(vec2))
.
Example 1: Create a Polygon geometry with no hole:
geo_polygon(list(list( vec2(origin()) + vec2(200000m, 600000m), vec2(origin()) + vec2(200050m, 600000m), vec2(origin()) + vec2(200050m, 600050m), vec2(origin()) + vec2(200000m, 600000m), )))
Example 2: Create a Polygon geometry with one hole:
geo_polygon(list( list( // outer polygon vec2(origin()) + vec2(200000m, 600000m), vec2(origin()) + vec2(200050m, 600000m), vec2(origin()) + vec2(200050m, 600050m), vec2(origin()) + vec2(200000m, 600000m), ), list( // inner hole vec2(origin()) + vec2(200025m, 600025m), vec2(origin()) + vec2(200035m, 600025m), vec2(origin()) + vec2(200035m, 600035m), vec2(origin()) + vec2(200025m, 600025m), ), ))
get_centroid
get_centroid(object)
Returns the centroid of the given object/geometry.
geo_intersect
geo_intersect(geom1, geom2)
Returns true if geom1
and geom2
intersect/overlap.
On a span,
geo_intersect(pole1.geometry, pole2.geometry)
returnsfalse
On a span,
geo_intersect(geometry, pole1.geometry)
returnstrue
get_outline_interval_points
get_outline_interval_points(geom, interval:10.0m)`
Returns a list of location vectors along the outline of the geometry at the given interval. \Point and MultiPoint are simply expanded into points.
Example:
get_outline_interval_points( geo_linestring( list(index(model().Spans, 0).pole1.location, index(model().Spans, 0).pole2.location), list(index(model().Spans, 1).pole1.location, index(model().Spans, 1).pole2.location), ), interval: 5m)
returns a list of location vectors.
geo_query
geo_query(collection, geometry, distance)
Queries a collection of geometric objects returning those that are within some distance of the given geometry, in order of closest to furthest.
The second argument can either be a geometry or a type that has a geometry field.
For example, using pole is equivalent to using pole.geometry.
Example: Find all poles within 10m of the given pole using: geo_query(model().Poles, pole, 10m)
slice_catenaries
slice_catenaries(catenaries, [start_ratio: 0.0, end_ratio: 1.0, num_slices: 1])
Get the catenaries corresponding to the portions of the original catenaries within the specified ratio interval.
If start_ratio
or end_ratio
are outside the range [0.0, 1.0]
, the slices will be extended in to meet the specified ratio along their respective curves.
There is an option to slice the portion of catenaries into multiple slices using num_slices parameter.
Valid range for number of slices is
[1, 100]
Catenaries with blowout are not currently supported; such catenaries will produce no slices.
Examples:
slice_catenaries(catenaries, start_ratio: 0.1, end_ratio: 0.9)
returns the middle 80% of the specified catenaries.s
lice_catenaries(catenaries, start_ratio: 0.2, end_ratio: 0.5 num_slices: 3)
returns, for each catenary, a sequence of slices between the following points on the curve:20%-30%-40%-50%
slice_line
slice_line(line, num_slices)
Slices line in equal parts. Limited to 100 slices.
convex_area
convex_area(geometry)
Returns the area of the convex hull of the given geometry
make_wedges
make_wedges(catenaries, angle, height, [downward: true])
Creates wedge-shaped volumes pointing either downward (if downward = true
) or upward using the endpoints (instead of the curves) of catenaries, where the angle between the two sides of each wedge is [angle]
and the triangular face of each wedge is [height]
tall.
Example on a span:
make_wedges( Environments[].Cables, unit_value(75, "degrees"), 4m )
origin
origin()
Returns the coordinate origin as a Vector3 of absolute distance values.
Example: origin().z + 100m
returns 100m
of altitude as an absolute value.