Section Line Indicators#

from pathlib import Path
from dessia_drawing.core import Drawing
from drawing_tools.config.default_language_configs import DEFAULT_ENGLISH_CONFIG, DEFAULT_FRENCH_CONFIG
from drawing_tools.featured_drawing import FeaturedDrawing

_DATA_DIR = Path("data/json")
drawing = Drawing.from_json(str(_DATA_DIR / "condor/condor_BEAM_ASSY.json"))
featured_drawing = FeaturedDrawing(drawing, language_configs=[DEFAULT_FRENCH_CONFIG, DEFAULT_ENGLISH_CONFIG])
featured_sheet = featured_drawing.sheets[3]
featured_view = featured_sheet.views[3]
featured_view.plot_data_section_lines().plot()
featured_sheet.plot_data_section_lines().plot()

Section line indicators are symbols on technical drawings that show where a section cut or auxiliary view is taken. Drawing Tools detects them automatically and provides structured access to their properties.

See also

For a complete working example demonstrating section line detection, see the script scripts/section_lines_and_auxiliary_view_indicators.py in the repository.

What is a Section Line Indicator?#

A section line indicator consists of:

  • Two collinear arrows pointing in the same direction, marking the cut line

  • A letter identifier on each arrow (e.g., “A”, “B”, “K”)

  • Optionally, a cross-reference to a sheet number (e.g., “4/5” meaning sheet 4 of 5)

      A            A
      |            |
------+------------+------
      v   4/5      v

These symbols indicate where section views (e.g., COUPE A-A), detail views, or auxiliary views are cut from. The identifier letter corresponds to the view title on the target view (e.g., a section line “A” produces the view “COUPE A-A”).

Accessing Section Line Indicators#

Section line indicators are detected automatically on each FeaturedView:

for sheet in featured_drawing.sheets:
    for view in sheet.views:
        for indicator in view.section_line_indicators:
            info = indicator.identifier_info
            print(f"{info.identifier} cross_ref={info.cross_reference} "
                  f"detection_source={indicator.detection_source}")

SectionLineIndicator Properties#

Each SectionLineIndicator provides:

  • ``identifier_info`` — an IdentifierInfo object containing:

    • identifier: full identifier string (e.g., "A", "B2")

    • letter: letter part (e.g., "A", "B")

    • number: numeric suffix or None (e.g., 2 in "B2")

    • cross_reference: sheet cross-reference string (e.g., "4/5") or None

    • cross_reference_left: sheet number (e.g., 4) or None

    • cross_reference_right: total sheets (e.g., 5) or None

  • ``arrow_locations`` — list of two Point2D positions (the two arrow tips)

  • ``arrow_direction``Vector2D shared direction of both arrows

  • ``detection_source`` — how the indicator was detected:

    • "symbols" — from a single TypeNote annotation with FillArrow leaders

    • "symbols (standalone xref)" — same, but cross-reference was a separate text

    • "composites" — from CompositeEntity arrows paired with standalone TypeNote labels

  • ``source_entities`` — the original dessia_drawing entities

View-Level Visualization#

The following visualization shows section line indicators detected on the “DETAIL 2” view of the BEAM ASSY drawing (Sheet 3). Each indicator is highlighted with a colored bounding rectangle and labels showing its identifier, cross-reference, detection source, and arrow direction.

Source: condor_BEAM_ASSY.json, Sheet 3, DETAIL 2

featured_view = featured_drawing.sheets[3].views[3]  # DETAIL 2
featured_view.plot_data_section_lines().plot()

Sheet-Level Visualization#

Section line indicators can also be visualized at the sheet level, showing all indicators across all views on a single sheet:

Source: condor_BEAM_ASSY.json, Sheet 3

featured_sheet = featured_drawing.sheets[3]
featured_sheet.plot_data_section_lines().plot()

Each indicator is assigned a different color from a rotating palette to distinguish overlapping indicators.

Detection Sources#

Section line indicators can be encoded in two different ways in CAD files. Drawing Tools handles both representations transparently:

Symbols (detection_source="symbols"): A single TypeNote annotation carries both the arrows (as FillArrow leaders) and the text labels. This is the most common representation.

Composites (detection_source="composites"): Each arrow is a separate CompositeEntity and the letter labels are standalone TypeNote annotations positioned nearby. The detector matches labels to arrows by spatial proximity, then groups arrow pairs by identifier and collinear direction.

Both sources are merged in the section_line_indicators property. You can check indicator.detection_source to know which representation was used. To see the code behind the two branches, see Going Further at the end of this page.

Counting Indicators#

# Number of section line indicators in a view
count = featured_view.section_line_indicator_count

# Iterate and filter
indicators_with_xref = [
    ind for ind in featured_view.section_line_indicators
    if ind.identifier_info.cross_reference is not None
]

Going Further: Inside the Detection#

For readers who want to see how the detector works

Two classes carry this feature, both in view/annotations/section_line_indicator.py:

  • the featureSectionLineIndicator, the value object described above, with its IdentifierInfo, its arrow locations and direction and its detection_source;

  • the detectorViewSectionLineDetector, which holds the recipe and its SectionLineDetectionConfig. FeaturedView.section_line_indicators builds one per view; the sheet property concatenates the results.

detect_all is one line: the symbols branch plus the composites branch of Detection Sources. The symbols branch (_extract_from_symbols) walks the view’s TypeNote annotations and keeps those with exactly two collinear FillArrow leaders (_get_valid_symbol_arrow_pair) and a duplicated identifier in their texts (_extract_duplicated_identifier_info, completed by _complete_identifier_info_with_duplicated_xref). The composites branch is a four-step pipeline:

def _extract_from_composites(self) -> list[SectionLineIndicator]:
    """Detect section line indicators from CompositeEntity arrows + standalone TypeNote labels.

    In this representation, each arrow is a separate CompositeEntity and the letter
    labels (e.g., ``"A"``, ``"K 4/5"``) are standalone TypeNote annotations positioned
    nearby. Detection follows a four-step pipeline:

    1. ``_get_composite_arrow_candidates``: collect CompositeEntity arrows with valid geometry.
    2. ``_collect_identifier_notes``: collect TypeNote labels matching the indicator pattern.
    3. ``_match_arrows_to_identifiers``: spatially match each label to its nearest arrow.
    4. ``_group_identified_arrows``: group arrows by matching identifier + collinear direction.

    Then ``_build_indicators_from_groups`` filters valid pairs and builds indicators.
    """
    single_arrow_candidates = self._get_composite_arrow_candidates()
    if len(single_arrow_candidates) < self.config.min_leaders_for_indicator:
        return []

    identifier_notes, identifier_infos = self._collect_identifier_notes()
    identified_arrows = self._match_arrows_to_identifiers(
        identifier_notes, identifier_infos, single_arrow_candidates
    )
    grouped_identified_arrows = self._group_identified_arrows(identified_arrows)
    return self._build_indicators_from_groups(grouped_identified_arrows)
  • _get_composite_arrow_candidates reads the arrows drawn as CompositeEntity (collect_composite_arrows in composite_arrows.py, shared with the auxiliary view indicators);

  • _collect_identifier_notes keeps the standalone notes reading as an identifier;

  • _match_arrows_to_identifiers gives each note its nearest arrow;

  • _group_identified_arrows pairs arrows carrying the same identifier whose tips lie on one perpendicular line, and _build_indicators_from_groups keeps the valid pairs.

The step-by-step walkthrough, with the geometry of each test, is in Section Line Indicator Detection Pipeline.