Clash panel

True Distance

The real perpendicular distance between two measured faces, unaffected by project rotation or an off-square click.

On the ribbonButton, Clash panel
NeedsAn open document
Shift+ClickThe fraction feet-and-inches readings round to, and how far two faces may tilt and still count as parallel

What it does#

A rotated project makes the measure tool's X, Y and Z readouts meaningless, and the straight line overshoots whenever the two clicks are not exactly opposite each other. This reports the gap, not the line: the measured vector projected onto the faces' shared normal, which is the number a tape held square to the faces would give.

How to use it#

  1. Click True Distance. The native Point to Point tool opens.
  2. Click a point on the first face, then a point on the second. Snap to corners if you like; the result is the same.
  3. Read the banner across the bottom of the window. Green: both faces found and parallel. Amber: only one face found, measured square to that one. Red: no face under either point.

Limitations#

  • Both points must sit on real geometry. A point in empty space has no face.
  • Faces more than the tolerance apart in angle are reported as not parallel, with the angle, and the reading falls back to the first face.
  • The banner stays about eight seconds; the dimension drawn in the view stays until the next run.

Other uses#

  • Floor to ceiling heights: horizontal faces are parallel faces too.
  • Checking a clearance someone claims was fixed, without trusting a diagonal line.

Good to know#

On an imperial document the reading matches the native readout style, and the rounding fraction is yours to set. Settings live in true_distance.json.

Source#

The tool's own files, word for word as shipped in Clash.panel/True_Distance.pushbutton. Every pyNavis tool is an ordinary bundle: copy these into your own extension and change what you like.

script.py Runs on a click. View on GitHub
"""Perpendicular distance between the two faces the current measurement
touches.

A rotated project makes the measure tool's X/Y/Z readouts meaningless and
the straight line overshoots whenever the two clicks are not exactly
opposite each other. A click starts a native point-to-point measurement
(pynavis.pick.measure_points), waits for its two points, finds which faces
each point sits on from the items' own triangles (pynavis.faces), and shows
the measurement projected onto the normal of the parallel pair on a banner
across the bottom of the window. The native measurement is dropped as soon
as its two points are in and the previous tool comes back; the same value
is drawn in the view as a dimension square to the faces and stays until
the next run. Everything above the guard at the bottom is importable
without Navisworks; see truedistance.py for the math.
"""

import truedistance

from pynavis import app, banner, faces, overlay, pick, script, settings
from pynavis.clash import units_to_meters

# Overlay tag for the dimension this tool draws; one at a time.
DIMENSION_TAG = 'true-distance'


def run():
    from pynavis._api import Api
    doc = app.get_doc()
    log = script.get_logger()
    # The dimension and banner from the last run make way for this one.
    overlay.clear(DIMENSION_TAG)
    overlay.redraw()
    banner.clear()
    measured = pick.measure_points('Click the first face', 'Now click the second face',
                                   notify=banner.prompt, keep=False)
    if measured is None:
        banner.clear()
        return                              # Esc, right-click or another tool: say nothing
    p1, p2 = measured

    values = settings.load(truedistance.TOOL, truedistance.DEFAULTS)
    view = doc.ActiveView
    first, end = Api.Point3D(p1[0], p1[1], p1[2]), Api.Point3D(p2[0], p2[1], p2[2])
    log.info('measurement %s -> %s, units %s' % (p1, p2, doc.Units))

    meters = units_to_meters(doc)
    tol = truedistance.tolerance_for((p1, p2), meters)
    floor = truedistance.tolerance_for((), meters)
    result = truedistance.resolve(
        p1, p2,
        faces.faces_under(view, first, tol, log, 'first', floor=floor)[0],
        faces.faces_under(view, end, tol, log, 'end', floor=floor)[0],
        parallel_degrees=float(values['parallel_degrees']))
    log.info('result %s' % result)

    units = str(doc.Units)
    denominator = int(values['denominator'])
    title, detail = truedistance.describe(result, units, denominator)
    if result['status'] == 'no-face':
        overlay.clear(DIMENSION_TAG)
        overlay.redraw()
        banner.error(title, detail)
        return
    if result['status'] == 'ok':
        banner.success(title, detail)
    else:
        banner.warning(title, detail)

    # The same value drawn in the view: a dimension square to the faces from
    # the first point, a dashed extension to the second. The measurement is
    # gone, so this is not anchored to it; the next run clears it.
    start, foot = truedistance.dimension(p1, p2, result['normal'])
    drawn = overlay.dimension(DIMENSION_TAG, start, foot,
                              truedistance.format_length(result['across'], units, denominator),
                              extension_to=p2)
    overlay.redraw()
    log.info('dimension %s -> %s drawn=%s' % (start, foot, drawn))


if '__commandpath__' in globals():
    run()
config.py Runs on Shift+Click. View on GitHub
"""Options for True Distance: fraction denominator and parallel tolerance."""

import truedistance

from pynavis import forms, settings, toast

values = settings.load(truedistance.TOOL, truedistance.DEFAULTS)

denominator = forms.ask_number(
    'Round feet-inches readings to this fraction of an inch (1/N):',
    default=values['denominator'], min_value=1, max_value=1024,
    title='True Distance')
if denominator is not None:                    # None means cancelled: change nothing
    degrees = forms.ask_number(
        'Treat two faces as parallel when their normals differ by no more than (degrees):',
        default=values['parallel_degrees'], min_value=0, max_value=45,
        title='True Distance')
    if degrees is not None:
        values['denominator'] = int(round(denominator))
        values['parallel_degrees'] = float(degrees)
        settings.save(truedistance.TOOL, values)
        toast.success('Saved', 'Fractions to 1/%d, parallel within %.1f deg.'
                      % (values['denominator'], values['parallel_degrees']))
bundle.yaml The bundle contract: the keys pyNavis reads for this tool. View on GitHub
title: True\nDistance
tooltip: True perpendicular distance between two faces, unaffected by project rotation, shown on a bar across the bottom of the window. Click, then measure the two faces with the native Point to Point tool it opens. Shift+Click for settings.
context: doc