Coordinate > Clash Results

Clash Heatmap

Colours elements by how many open clashes they have, lists the top hotspots, and can mark the densest spots in the view. Shift+Click clears the colours and markers.

Tab and panelCoordinate > Clash Results
KindButton
Live whenThe model has clash results

Status

Untested Never executed inside Navisworks. Passed the headless checks only.

The public ask

No public source is on record for this tool.

Events it listens to

None. It runs only when you click it.

Files

Paths are relative to the Playground.extension folder.

  • Coordinate.tab/Clash_Results.panel/Clash_Heatmap.pushbutton/bundle.yaml
  • Coordinate.tab/Clash_Results.panel/Clash_Heatmap.pushbutton/config.py
  • Coordinate.tab/Clash_Results.panel/Clash_Heatmap.pushbutton/icon.dark.png
  • Coordinate.tab/Clash_Results.panel/Clash_Heatmap.pushbutton/icon.png
  • Coordinate.tab/Clash_Results.panel/Clash_Heatmap.pushbutton/icon.small.dark.png
  • Coordinate.tab/Clash_Results.panel/Clash_Heatmap.pushbutton/icon.small.png
  • Coordinate.tab/Clash_Results.panel/Clash_Heatmap.pushbutton/script.py

Install

  1. Only this tool. In Navisworks, click pyNavis > Playground, search for Clash Heatmap, tick it and click Install.
  2. The whole extension. Download Playground.extension.zip, unzip it, put the Playground.extension folder in %APPDATA%\pyNavis\extensions\, and click pyNavis > Reload. Clash Heatmap is on the Coordinate tab, Clash Results panel.

You need pyNavis 1.3.0 or later.

Tried it? Tell us whether it worked or not. That report is what moves a tool up the status ladder.

Report

Source

The tool's own files, word for word as published in pynavis/Playground. Paths are relative to the Playground.extension folder.

script.py

The script that runs on a click.

Coordinate.tab/Clash_Results.panel/Clash_Heatmap.pushbutton/script.py View on GitHub
"""Colours elements by how many open clashes they have and marks the densest spots in the view."""
from pynavis import script, toast

from namo import clashheat, progress, ui, units
from namo import clashset_common as common
from namo import clashset_tests as defs

DEFAULTS = {'tests': [], 'statuses': list(common.OPEN_STATUSES), 'ghost': True, 'markers': False,
            'cell_m': clashheat.DEFAULT_CELL_M}
TITLE = 'Clash Heatmap'


def ask(values, doc_units):
    fields = [
        {'kind': 'multi', 'key': 'statuses', 'label': 'Count clashes with these statuses',
         'options': [(s, s) for s in common.STATUS_NAMES], 'default': values['statuses']},
        {'kind': 'check', 'key': 'ghost', 'label': 'Ghost the elements without clashes',
         'default': values['ghost']},
        {'kind': 'check', 'key': 'markers', 'label': 'Mark the densest spots in the view',
         'default': values['markers']},
        {'kind': 'length', 'key': 'cell', 'label': 'Marker cell size', 'required': True,
         'default': units.from_meters(values['cell_m'] or clashheat.DEFAULT_CELL_M, doc_units),
         'min': 0.0001, 'enabled_if': ('markers', True)},
    ]

    def validate(answers):
        if not answers['statuses']:
            return {'statuses': 'Tick at least one status.'}
        return None

    return ui.form(TITLE, fields, ok='Show', validate=validate, units=doc_units,
                   intro='Every chosen clash counts once for each of its two elements.')


def run():
    from pynavis import doc as pdoc
    doc = pdoc.get_doc()
    problem = common.clash_problem(doc, need_results=True)
    if problem:
        toast.show(*problem)
        return
    values = script.get_config(DEFAULTS)
    tests = common.choose_tests(TITLE, 'Tick the tests to count.', values['tests'], doc=doc)
    if tests is None:
        return
    if not tests:
        toast.info('No clash results yet', 'Run your clash tests in Clash Detective first.')
        return
    doc_units = defs.doc_units(doc)
    answers = ask(values, doc_units)
    if answers is None:
        return
    values.update({'statuses': answers['statuses'], 'ghost': answers['ghost'],
                   'markers': answers['markers'], 'tests': [t.DisplayName for t in tests]})
    if answers.get('cell'):
        values['cell_m'] = units.to_meters(answers['cell'], doc_units)
    script.save_config(values)
    try:
        entries = common.read_entries(tests, doc)
    except RuntimeError as error:
        toast.error('Could not read the clashes', str(error))
        return
    if entries is progress.CANCELLED:
        return
    counts, elements, names, centres = clashheat.collect(entries, answers['statuses'])
    if not counts:
        toast.info('No clashes to count', 'None of the chosen tests has %s clashes.'
                   % ' or '.join(answers['statuses']))
        return
    coloured = common.write_progress(TITLE, lambda report_to: clashheat.show(
        counts, elements, answers['ghost'], doc))
    markers = 0
    overlay_ok = True
    if answers['markers']:
        cell = units.from_meters(values['cell_m'], doc_units)
        markers, overlay_ok = clashheat.draw_markers(centres, cell)
    legend = clashheat.legend(counts)
    title = 'Clash heatmap: %s' % ', '.join(e['name'] for e in entries)
    clashheat.report(counts, elements, names, legend, markers if overlay_ok else 0, title, doc)
    top_key, top_count = clashheat.ranked(counts, names, 1)[0]
    detail = 'Hotspot: %s with %s.' % (names.get(top_key) or 'an element',
                                       common.plural(top_count, 'clash', 'clashes'))
    if answers['markers'] and not overlay_ok:
        toast.warning(clashheat.summary_text(coloured, len(legend), 0),
                      'Markers need the pyNavis overlay; restart Navisworks to finish installing it.')
        return
    toast.success(clashheat.summary_text(coloured, len(legend), markers), detail)


if globals().get('__runner__'):
    toast.warning(*common.RUNNER_MESSAGE)
else:
    run()

config.py

The Shift+Click action.

Coordinate.tab/Clash_Results.panel/Clash_Heatmap.pushbutton/config.py View on GitHub
"""Clears the last clash heatmap: removes its markers and puts the element colours back."""
from pynavis import toast

from namo import clashheat

markers, reset = clashheat.clear()
if not markers and not reset:
    toast.info('No heatmap to clear', 'Run Clash Heatmap first; this clears what it drew.')
else:
    parts = []
    if reset:
        parts.append('colours reset')
    if markers:
        parts.append('{:,} marker{} removed'.format(markers, '' if markers == 1 else 's'))
    toast.success('Cleared the clash heatmap', ', '.join(parts).capitalize() + '.')

Library modules this tool uses

From the shared namo library, which installs with every tool. Each name opens the module on GitHub.

  • namo.clashheatClash Heatmap: which elements clash most, coloured by count, plus density markers.
  • namo.clashset_commonSmall things every Clash Setup and Clash Results tool shares.
  • namo.clashset_testsClash test definitions as plain data, and the one place Playground builds tests from them.
  • namo.progressGlue between pyNavis' cancellable progress window and Playground's progress callbacks.
  • namo.uiWPF building blocks for Playground tools, themed from the pyNavis design system.
  • namo.unitsUnits: document lengths, conversions, and quantities as people and Revit write them.

bundle.yaml

The bundle contract: the keys pyNavis reads for this tool.

Coordinate.tab/Clash_Results.panel/Clash_Heatmap.pushbutton/bundle.yaml View on GitHub
title: Clash\nHeatmap
tooltip: Colours elements by how many open clashes they have, lists the top hotspots, and can mark the densest spots in the view. Shift+Click clears the colours and markers.
context: clash-results