topologicpy
0.9.86

Contents:

  • topologicpy
    • topologicpy package
      • Submodules
        • topologicpy.ANN module
        • topologicpy.Aperture module
        • topologicpy.BVH module
        • topologicpy.CSG module
        • topologicpy.Cell module
        • topologicpy.CellComplex module
        • topologicpy.Cluster module
        • topologicpy.Color module
        • topologicpy.Context module
        • topologicpy.Core module
        • topologicpy.Dictionary module
        • topologicpy.Edge module
        • topologicpy.EnergyModel module
        • topologicpy.Face module
        • topologicpy.GA module
        • topologicpy.GQL module
        • topologicpy.GraphDB module
        • topologicpy.GraphRAG module
        • topologicpy.Grid module
        • topologicpy.Helper module
        • topologicpy.Honeybee module
        • topologicpy.IFC module
        • topologicpy.Kuzu module
        • topologicpy.LLM module
        • topologicpy.Matrix module
        • Navigation
        • topologicpy.Neo4j module
        • topologicpy.Ontology module
        • topologicpy.Plotly module
        • topologicpy.Polyskel module
        • topologicpy.PyG module
        • topologicpy.ShapeGrammar module
        • topologicpy.Shell module
        • topologicpy.Speckle module
        • topologicpy.Sun module
        • topologicpy.TGraph module
        • topologicpy.Topology module
        • topologicpy.Vector module
        • topologicpy.Vertex module
        • topologicpy.Wire module
        • topologicpy.version module
      • Module contents
topologicpy
  • »
  • topologicpy »
  • topologicpy package »
  • Navigation
  • View page source

Navigation

The navigation API separates source extraction, editable geometry, grid construction and graph analysis. It does not depend on SpatialLab or a web framework. Navigation sampling and geometry helpers reside in Navigation.py; IFC mesh adaptation and extraction helpers reside in IFC.py as private class methods. Existing Grid.OnFace is unchanged.

Quick start

from topologicpy.IFC import IFC
from topologicpy.Navigation import Navigation

source = IFC.ModelByPath("building.ifc")
model = IFC.NavigationModel(source)
graph = Navigation.Graph(model, spacing=1.0)
tiles = Navigation.Tiles(model, graph)
eye_faces = Navigation.IsovistFaces(model, eyeHeight=1.6)

Navigation.ByIFCPath(path) combines the first two calls. Parsing happens once; changing graph spacing does not reparse the IFC. A 2D face uses the same model:

model = Navigation.ByFaces([face], obstacles=[obstacle_footprint])
graph = Navigation.Graph(model, spacing=0.5)

Model and geometry

NavigationModel.faces and obstacles contain actual Topologic Faces; connectors contain geometry descriptors made by Stair, Ramp and Lift. storeys contains dictionaries with id, name and elevation. Face dictionaries carry storey and source identifiers. Users may edit the geometry and construct another graph. Replacing the imported obstacle footprint list overrides solid sectioning with the supplied footprint geometry. Footprint obstacles passed to ByFaces are assigned to the nearest elevation unless they already carry a storey identifier. storeyIDs can explicitly assign the walking faces.

Coordinates use world Z as up. Faces must have linear boundaries, be planar and have a nonzero XY projection; horizontal and sloping faces are supported. IFC coordinates are normalized to metres. Direct geometry inputs retain their model units, so spacing, step heights and eye heights must use those same units. Intrinsic grids on curved surfaces remain available through Grid.OnFace.

IFC extraction excludes roofs and uses containment before elevation fallback. maxSlope selects candidate slab slopes in degrees (default 45). An upward surface alone is not proof of operational walkability. obstacleTypes can restrict physical obstacle classes; None uses all supported physical obstacles. excludeTypes excludes selected IFC classes from extraction. Furniture and opening geometry use conservative world-aligned boxes; opening boxes cut their hosts. The model metadata includes an omittedSurfaces list for native face conversion failures, without printing warnings. Unsupported geometry is best effort and disconnected components remain disconnected.

Connectors

  • Navigation.Stair(topology_or_faces, ...) selects horizontal tread/landing surfaces. A single descriptor groups its faces into one assembly. Separate descriptors may share group to join a stair and its landings.

  • Navigation.Ramp(topology_or_faces, spacingRatio=0.15, ...) samples the inferred centreline at a fraction of its 3D length. Absolute spacing overrides the ratio. Endpoints and detected flat landings are retained. Disjoint or non-monotonic geometry may not yield a centreline; supply an ordered centreline (XYZ points, Vertices, or a linear Wire) to bypass inference. Supplied centreline corners are always retained. Without surface geometry, explicit centreline nodes have no colour tiles.

  • Navigation.Lift(doors, cabinCentres, storeys=None, ...) accepts matching ordered lists, with one door and cabin point per level. Door and cabin points must share an elevation. Cabin points connect in elevation order; doors attach to floor grids. Lifts have no dedicated colour tiles.

Graph construction

Navigation.Graph returns a TGraph with navigation nodes, edges and tile metadata. Use TGraph analysis and shortest-path methods on the result. Edge dictionary Length is Euclidean distance in model units, so geometric routing uses TGraph.ShortestPath(graph, start, end, edgeKey="Length").

The default graph connects adjacent clipped grid cells. mode="visibility" adds same-storey visibility connections while checking surface discontinuities. origin and direction define a shared XY grid frame. storey restricts construction to one storey before routing, preventing detours through other levels. The model itself is not changed.

The default maximum vertical slab step is 0.17 model units. Horizontal gaps are never bridged (apart from numerical tolerance): maxHorizontalGap must be zero. Explicit connectors can describe intentional bridges. Tread-to-tread connections require touching geometry from the same connector assembly; extracted stair rises above maxStairRiser (default 0.35 model units) remain disconnected. Connector attachments use the nearest reachable floor-grid point. Invalid spacing, unsupported modes and empty walking geometry raise explicit exceptions.

Overlapping coplanar floor faces are merged before gridding. sourceIDs retains the contributing source identifiers for each merged region. Coincident connector and grid points on the same storey share one vertex; kinds retains their combined classifications. Coincident points with different storey identifiers remain separate vertices, with separate tile associations. Inter-storey routes require explicit connector edges.

Vertices carry navigationID, storey, source, kind and tileIDs. Edges carry Length and kind. Navigation.Tiles(model, graph) requires a TGraph and returns Topologic Faces with navigationID and tileID dictionaries. Tile geometry is stored as JSON in the graph dictionary so it survives graph serialization; associations describe the graph at construction time, even if the source model is later edited. A node may own multiple tiles. Graphs without navigation tile metadata return an empty tile list.

Navigation.IsovistFaces returns strictly horizontal faces at every walking elevation plus eye height. IFC solids are sectioned again at the requested eye height. Direct planar obstacles are treated as vertical footprints. Results can be restricted to a storey and passed to existing planar isovist methods.

Grid.OnFaces produces shared, clipped grid-line geometry on several planar faces. It uses the same XY projection convention as navigation, whereas Grid.OnFace retains its existing surface-grid behavior.

Exact visibility performance

mode="visibility" calls TGraph.VisibilityGraph for line-of-sight construction. Both classes now use the same conservative corner-contact rule: a boundary corner inside a sightline blocks it, even when contact is tangential. This deliberately replaces Navigation’s former permissive tangency rule. Local floor links in visibility mode cannot bypass the shared engine.

Navigation adds its physical constraints after shared visibility: exact cleared floor support and elevation/step-height continuity. Coplanar models need no height-interval reconstruction. These filters are batched; geometry is prepared once per storey. No distance or neighbour cutoff is applied.

useNumba=False uses TGraph’s angular-event/direct Python engine without compilation delay. useNumba=True requests its optional compiled full-visibility engine, with the same Python fallback if unavailable. The same option and engine are used by both classes; compiled first-use overhead can exceed its warm-call savings on small models.

Keyword-only construction controls are available:

graph = Navigation.Graph(model, mode="visibility",
                         visibilityBatchSize=4096,
                         maxVisibilityPairs=5_000_000,
                         maxVisibilityEdges=1_000_000, useNumba=False)

All three values must be positive integers. The pair limit is checked before visibility candidate geometry is allocated. The edge budget applies to temporary shared visibility graphs as well as final visibility/connector construction, before coincident-node merging. Exceeding a budget raises ValueError; construction never silently returns a truncated graph. Increase spacing, use local mode="navigation", or explicitly raise the relevant limit. Batching reduces geometry overhead, but a fully visible set of n nodes still requires n(n-1)/2 edges.

Clearance

graph = Navigation.Graph(model, spacing=1.0, clearance=0.3)

Clearance is a horizontal XY margin in model units (metres for IFC models). The default zero preserves existing construction. Obstacles are subtracted first, then physically joined walking regions are offset using Face.ByOffset. Internal slab boundaries and permitted small steps remain connected. A narrow passage can close or split a region; no links are fabricated across that split. If no floor region survives, graph construction raises ValueError.

The grid origin and cell spacing stay fixed. Boundary samples move into the surviving portion of their original cell. Original display tiles remain attached to those samples, so an inset does not automatically create an uncoloured band along every wall. Consumed cells disappear; cells split into several components retain separate tiles. Where a concave cell prevents a straight connection, extra bend nodes keep the route inside the valid cleared region. These junctions have no dedicated colour tiles and participate in graph analyses normally.

Stair and ramp width is tested across the assembled passage, retaining internal tread and landing connections. Attachment corridors are checked for width and obstacles when choosing reachable floor samples. A connector that is too narrow remains disconnected. Supplied ramp surfaces are used even with an explicit centreline; geometry-free centrelines and lift cabin edges do not supply width information and retain their explicit connections. Navigation.Lift accepts an optional footprint Face to preserve door portals during clearance; the IFC adapter supplies the shaft footprint automatically. This is a geometric XY constraint, not an accessibility or headroom assessment. Isovist faces are unchanged; their grid can independently use Grid.OnFace clearance if desired.

The margin is stored in the graph dictionary as clearance and applies to the returned TGraph. All implementation helpers remain within Navigation.py, Grid.py and the corresponding existing backend class files.

Isovist boundary roles

Navigation.IsovistFaces labels every returned internal Wire using isovistType="hole" for a genuine floor void and isovistType="obstacle" for a region intersecting an eye-level obstacle. IFC solids are sectioned at the requested eye height; generic planar obstacles retain their vertical-footprint interpretation. Merged void and obstacle boundaries are classified as opaque as a whole, even if the obstacle occupies only part of the enclosed region.

Face.Isovist reads these labels automatically: it rejects viewpoints in both types but sees across transparent holes. The source walking faces and the navigation graph remain unchanged, and the returned eye-level faces still exclude both types from grid sampling. Pass boundaryTypeKey to both methods when using a custom dictionary key:

eye_faces = Navigation.IsovistFaces(model, boundaryTypeKey="visibilityRole")
visible = Face.Isovist(eye_faces[0], viewpoint,
                      boundaryTypeKey="visibilityRole")

API reference

Geometry-first, multi-level navigation models and graph construction.

Navigation coordinates are model units with world Z as up. IFC extraction normalizes coordinates to metres. Planar faces may slope but must have a nonzero XY projection. No spatial links are inferred across horizontal gaps.

class topologicpy.Navigation.Navigation

Bases: object

Static methods for constructing and querying navigation models.

Methods

ByFaces(faces[, obstacles, connectors, ...])

Create a model from planar horizontal/sloping Faces.

ByIFCPath(path[, eyeHeight, maxSlope, ...])

Parse an IFC path once and extract a metre-based model.

Graph(model[, spacing, maxStepHeight, ...])

Return a TGraph with persistent tile associations.

IsovistFaces(model[, eyeHeight, storey, ...])

Return horizontal Faces at each storey/walking elevation + eyeHeight.

Lift(doors, cabinCentres[, storeys, source, ...])

Describe a lift with one door and cabin point per served level.

Ramp([ramp, spacing, spacingRatio, ...])

Describe ramp top Faces, or an explicit ordered centreline.

ShortestPath(model, graph, start, end[, ...])

Route node indices, Topologic vertices or XYZ endpoints through TGraph.

Stair(stair[, storey, source, group, kind])

Describe horizontal tread/landing Faces of a Stair topology or list.

Tiles(model, graph[, storey])

Return tile Faces from a TGraph with navigationID and tileID metadata.

static ByFaces(faces, obstacles=None, connectors=None, storeys=None, storeyIDs=None, tolerance=1e-05)

Create a model from planar horizontal/sloping Faces.

Obstacles are planar footprints at walking elevation. Solid IFC obstacles are sectioned by IFC.NavigationModel. storeyIDs, when given, must parallel faces. Otherwise face dictionary storey values are used, falling back to rounded face elevations. Units are unchanged.

static ByIFCPath(path, eyeHeight=1.6, maxSlope=45.0, obstacleTypes=None, excludeTypes=None)

Parse an IFC path once and extract a metre-based model.

static Graph(model, spacing=1.0, maxStepHeight=0.17, maxHorizontalGap=0.0, storey=None, mode='navigation', origin=None, direction=None, tolerance=1e-05, maxStairRiser=0.35, clearance=0.0, *, visibilityBatchSize=4096, maxVisibilityPairs=5000000, maxVisibilityEdges=1000000, useNumba=False)

Return a TGraph with persistent tile associations.

mode is ‘navigation’ (adjacent grid cells) or ‘visibility’. Grid spacing is measured in XY, projected onto each surface. origin and direction define a shared XY frame. Horizontal gap bridging is unsupported; maxHorizontalGap must be zero. Storey restriction removes other levels before routing. Vertex dictionaries include navigationID/storey/kind/ source/tileIDs; edges include Length/kind. Units match the model.

clearance is a nonnegative horizontal XY margin in model units, default 0. Obstacles are subtracted before joined walking patches are inset via Face.ByOffset. Grid cells keep their origin/spacing; boundary sample positions can move into the usable part of the original cell. Display tiles retain original geometry when a cell has one surviving component. Split cells retain separate tiles, and consumed cells have no node. Narrow passages close without bridging. Clipped concave cells may add uncoloured bend nodes to follow a valid route inside the cleared region. Stair/ramp width and attachment corridors are checked across assembled footprints, rather than offsetting every tread along travel. Explicit geometry-free centrelines and cabin edges have no width to infer. Curved/nonplanar grids require a separate clearance definition.

Visibility uses TGraph.VisibilityGraph with conservative corner contacts. Navigation then checks floor support and elevation intervals in batches. useNumba selects TGraph’s optional compiled engine (default False). visibilityBatchSize bounds candidate geometry batches (default 4096). maxVisibilityPairs limits the same-storey candidate count (default 5000000); maxVisibilityEdges limits constructed visibility and connector edges (default 1000000). These keyword-only limits are positive integers. Exceeding a limit raises ValueError; no edges are silently dropped. Full visibility can still require quadratic output.

static IsovistFaces(model, eyeHeight=None, storey=None, boundaryTypeKey='isovistType')

Return horizontal Faces at each storey/walking elevation + eyeHeight.

IFC solid obstacles are resectioned at the requested eye height. Generic planar obstacles are treated as vertical footprints. Returned internal Wires carry boundaryTypeKey (default “isovistType”) with value “hole” for genuine floor voids or “obstacle” when the enclosed region intersects an eye-level obstacle. Merged void/obstacle boundaries are opaque as a whole. These labels are consumed directly by Face.Isovist; both types remain excluded from viewpoint grids. Source geometry/dictionaries are not modified.

static Lift(doors, cabinCentres, storeys=None, source=None, footprint=None)

Describe a lift with one door and cabin point per served level.

Inputs are equal-length ordered lists of XYZ coordinates or Vertices. Cabin points are joined in elevation order; each door joins its cabin. Only door points attach to floor grids. Lifts have no colour tiles. An optional planar Face footprint supplies shared cabin/shaft support for clearance at door portals. IFC extraction supplies it automatically; its XY projection is used at each served elevation.

static Ramp(ramp=None, spacing=None, spacingRatio=0.15, centreline=None, storey=None, source=None, group=None)

Describe ramp top Faces, or an explicit ordered centreline.

spacing is a positive absolute distance and overrides spacingRatio. Ratios refer to 3D centreline length. Surface extraction is best effort; an explicit centreline bypasses automatic elevation-slice inference.

static ShortestPath(model, graph, start, end, startStorey=None, endStorey=None, maxSnapDistance=None, edgeKey='Length', tolerance=1e-05, *, straighten=False)

Route node indices, Topologic vertices or XYZ endpoints through TGraph.

Return a dictionary with status, message, coordinates, nodeIDs, length, cost, snapDistances and wire. Geometric failures return an empty route with a descriptive status; invalid arguments raise ValueError/TypeError. Coordinate attachments use the graph’s saved floor/clearance snapshot. Floor coordinates attach inside a supported planar patch. Connector coordinates attach to their own saved tread/ramp/cabin surfaces or lie on an existing 3D connector segment. No nearest-airborne snapping is performed. Ambiguous intersecting connectors require node indices. maxSnapDistance bounds each endpoint-to-node connection, in model units (None is unlimited). Non-Length edge costs require endpoints resolving to existing nodes. straighten=True calls Wire.Straighten on floor-only runs, retaining connector edges and checking every replacement against saved clearance and height support. This requires edgeKey=”Length”. Neither graph nor model is modified. Rebuild after editing geometry.

static Stair(stair, storey=None, source=None, group=None, kind='tread')

Describe horizontal tread/landing Faces of a Stair topology or list.

Extraction keeps horizontal upward surfaces from solids; explicitly supplied Faces are treated as walking faces regardless of winding. kind=’landing’ describes an explicit landing.

static Tiles(model, graph, storey=None)

Return tile Faces from a TGraph with navigationID and tileID metadata.

Associations are captured on the graph at construction time, so results remain stable if the source model is later edited. Lift nodes have none.

class topologicpy.Navigation.NavigationModel(faces: list = <factory>, obstacles: list = <factory>, connectors: list = <factory>, storeys: list = <factory>, metadata: dict = <factory>, _ifc: dict = <factory>)

Bases: object

Editable navigation geometry, independent of any application.

faces and obstacles contain Topologic Faces. Face dictionaries retain storey/source identifiers. connectors contain the descriptors produced by Stair, Ramp and Lift. Storeys are dictionaries with id/name/elevation. Rebuilding a graph reads current geometry; parsing is never repeated.

connectors: list
faces: list
metadata: dict
obstacles: list
storeys: list

Routing queries

Navigation.ShortestPath(model, graph, start, end, startStorey=None, endStorey=None, maxSnapDistance=None, edgeKey="Length", tolerance=0.00001, straighten=False) resolves endpoints and delegates pathfinding to TGraph.ShortestPath. Endpoints may be stable TGraph node indices, Topologic vertices, or XYZ lists or tuples. Indices select an exact node; coordinate inputs matching multiple storeys require explicit storey identifiers, even at an existing grid point.

The returned dictionary contains status, message, coordinates, nodeIDs, length, cost, snapDistances and wire. Successful queries have status ok. Geometric failures return empty routes with status ambiguous_endpoint, endpoint_unreachable or disconnected and a human-readable message. Invalid arguments raise exceptions. nodeIDs are stable indices in the input graph; temporary coordinate endpoints use None. length is geometric length in model units, while cost uses edgeKey. wire is absent for zero-length routes or where geometry cannot represent the path. Existing-node queries retain the input graph topology.

Coordinate endpoints connect to reachable nodes through straight segments within a single saved planar floor patch, including its holes and clearance envelope. Every eligible node is considered, rather than selecting a nearest node across a wall. Two temporary endpoints can also connect directly on a shared patch. maxSnapDistance bounds these endpoint connections; None is unlimited. snapDistances reports the first and last connection lengths (zero for an existing-node endpoint). Connection distances contribute to route cost. Custom edge costs require existing-node endpoints because no cost model is inferred for temporary connections.

Routing floor support, construction tolerance, clearance, step/riser limits, spacing and mode are saved in the graph’s JSON navigationRouting dictionary. The snapshot survives TGraph serialization and copying. Neither the graph nor model is changed by a query. Model edits require rebuilding the graph; graphs built before this metadata was introduced must also be rebuilt. Inter-storey travel follows explicit graph connectors. Floor attachments do not bridge separate floor planes.

Connector coordinate endpoints

Coordinates on stair treads, landings, ramp surfaces and supplied lift cabin footprints attach only to their own saved connector nodes. Width checks use the saved connector footprint with obstacle cuts; they do not erode every stair riser as though it were an external wall. Coordinates on an existing 3D stair/ramp/lift segment attach along that segment, with partial lengths included in the cost. Two endpoints on the same segment can travel directly between their positions. Directed segments preserve their direction.

No off-surface or off-centreline projection is inferred. A lift without a cabin footprint therefore accepts its actual graph segments and nodes, not arbitrary positions elsewhere in the cabin. A segment between storeys uses its lower endpoint’s storey by default; an explicit storey may select either endpoint’s storey. Coordinates intersecting separate connector segments/surfaces are reported as ambiguous instead of creating a new connection between them.

Checked straightening

straighten=True calls Wire.Straighten on consecutive floor-only runs supported by one saved planar floor patch. Connector edges, their endpoint connections and changes of storey or support plane remain fixed. Proposed results must be ordered subsequences of the original run, retain its endpoints, and have every replacement segment inside the saved clearance envelope at the correct height. Invalid proposals retain the original run. Snap-distance limits are also retained. This option requires edgeKey="Length"; returned coordinates, node IDs, Wire, geometric length and cost describe the resulting route.

Example:

graph = Navigation.Graph(model, spacing=1.0, clearance=0.2)
route = Navigation.ShortestPath(
    model, graph, [1.2, 2.3, 0.0], [8.1, 4.7, 0.0],
    startStorey="ground", endStorey="ground", maxSnapDistance=2.0)
if route["status"] == "ok":
    points = route["coordinates"]
    length = route["length"]
Previous Next

© Copyright 2026, Wassim Jabi.

Built with Sphinx using a theme provided by Read the Docs.