Skip to content

Branch Corners

This guide explains the branch corner coordinate system for defining polyline paths between nodes. Understanding this system is critical for creating visually correct network diagrams.

Full Example

View the complete code: 11_branch_corners.py

The Corner System

Branch presentations use two coordinate lists to define the visual path:

ListDirectionDescription
first_cornersFrom Node1 outwardPolyline starting at Node1
second_cornersFrom Node2 outwardPolyline starting at Node2

The rendering engine draws a connection line between the last point of each list.

Critical Concept

second_corners must start at Node2, not end at it. This is counterintuitive but essential for correct rendering.

Visual Representation

Branch Corner System
10015020025030035040050100Node1Node2ABC
Afirst_corners: polyline starting from Node1, traveling outward
BConnection line: auto-drawn between last points of each list
Csecond_corners: polyline starting from Node2 (not ending!)

Example 1: Simple Straight Line

Two nodes at the same Y coordinate with a horizontal connection:

python
from pyptp.elements.mv.node import NodeMV
from pyptp.elements.mv.link import LinkMV
from pyptp.elements.mv.presentations import NodePresentation, BranchPresentation

# Nodes
node1 = NodeMV(
    NodeMV.General(name="A", unom=10.0),
    presentations=[NodePresentation(sheet=sheet_guid, x=100, y=100)],
)
node2 = NodeMV(
    NodeMV.General(name="B", unom=10.0),
    presentations=[NodePresentation(sheet=sheet_guid, x=300, y=100)],
)

# Branch
link = LinkMV(
    LinkMV.General(node1=node1.general.guid, node2=node2.general.guid),
    presentations=[
        BranchPresentation(
            sheet=sheet_guid,
            first_corners=[(100, 100), (200, 100)],  # From A, going right
            second_corners=[(300, 100)],              # At B
        )
    ],
)

Path: (100,100) → (200,100) ════ (300,100)

The connection line is drawn from (200,100) to (300,100).

Example 2: Right-Angle Bend

Nodes at different positions requiring a 90° turn:

python
# Node C at (100, 200), Node D at (300, 300)
link = LinkMV(
    LinkMV.General(node1=node_c.general.guid, node2=node_d.general.guid),
    presentations=[
        BranchPresentation(
            sheet=sheet_guid,
            first_corners=[(100, 200), (100, 250)],   # From C, going down
            second_corners=[(300, 300), (300, 250)],  # From D, going up
        )
    ],
)

Path: (100,200) → (100,250) ════ (300,250) ← (300,300)

The polylines meet at Y=250, creating a horizontal connection.

50100150200250300350400100150200CDAB
Polylines meet at Y=250, creating horizontal connection
Afirst_corners: [(100,200), (100,250)] (down from C)
Bsecond_corners: [(300,300), (300,250)] (up from D)

Example 3: Complex Zig-Zag with Diagonals

Multiple waypoints creating a complex path:

python
# Node E at (100, 400), Node F at (450, 450)
link = LinkMV(
    LinkMV.General(node1=node_e.general.guid, node2=node_f.general.guid),
    presentations=[
        BranchPresentation(
            sheet=sheet_guid,
            first_corners=[
                (100, 400),  # Start at E
                (150, 400),  # Right
                (200, 350),  # Diagonal up
                (250, 350),  # Right
                (300, 400),  # Diagonal down - last point
            ],
            second_corners=[
                (450, 450),  # Start at F
                (400, 420),  # Diagonal left-up
                (375, 410),  # More diagonal
                (350, 400),  # Final point - meets first_corners
            ],
        )
    ],
)

Path visualization:

100150200250300350400450100150200EF

Example 4: Minimal Specification

The simplest valid branch uses just the node positions:

python
link = LinkMV(
    LinkMV.General(node1=node_g.general.guid, node2=node_h.general.guid),
    presentations=[
        BranchPresentation(
            sheet=sheet_guid,
            first_corners=[(100, 550)],   # Just node G position
            second_corners=[(300, 550)],  # Just node H position
        )
    ],
)

Path: Direct line from (100,550) to (300,550).

Common Patterns

Horizontal Connection

python
first_corners=[(x1, y), (midpoint, y)]
second_corners=[(x2, y)]

Vertical Connection

python
first_corners=[(x, y1), (x, midpoint)]
second_corners=[(x, y2)]

L-Shape (Right Angle)

python
# Node1 at (100, 100), Node2 at (300, 200)
first_corners=[(100, 100), (100, 200)]  # Down from Node1
second_corners=[(300, 200)]              # At Node2

Z-Shape

python
# Node1 at (100, 100), Node2 at (300, 200)
first_corners=[(100, 100), (100, 150)]   # Down
second_corners=[(300, 200), (300, 150)]  # Up
# Connection at y=150

Validation

PyPtP validates that corner coordinates align with node positions. See Branch Corner Validation for details on the grid-based tolerance system.

Complete Example

python
"""Understanding branch corner coordinates and polyline construction.

CRITICAL: FirstCorners start FROM Node1 traveling outward.
          SecondCorners start FROM Node2 traveling outward.
          A connection line joins the last point of each.

Common mistake: SecondCorners must start at Node2, not end at it.
"""

from pyptp import NetworkMV, configure_logging
from pyptp.elements.color_utils import CL_GRAY
from pyptp.elements.mv.link import LinkMV
from pyptp.elements.mv.node import NodeMV
from pyptp.elements.mv.presentations import BranchPresentation, NodePresentation
from pyptp.elements.mv.sheet import SheetMV
from pyptp.ptp_log import logger

configure_logging(level="INFO")

network = NetworkMV()

sheet = SheetMV(SheetMV.General(name="Corner Examples", color=CL_GRAY))
sheet.register(network)
sheet_guid = sheet.general.guid

# Example 1: Simple straight line
node1 = NodeMV(
    NodeMV.General(name="A", unom=10.0),
    presentations=[NodePresentation(sheet=sheet_guid, x=100, y=100)],
)
node1.register(network)

node2 = NodeMV(
    NodeMV.General(name="B", unom=10.0),
    presentations=[NodePresentation(sheet=sheet_guid, x=300, y=100)],
)
node2.register(network)

link1 = LinkMV(
    LinkMV.General(node1=node1.general.guid, node2=node2.general.guid),
    presentations=[
        BranchPresentation(
            sheet=sheet_guid,
            first_corners=[(100, 100), (200, 100)],
            second_corners=[(300, 100)],
        )
    ],
)
link1.register(network)

# Example 2: Right-angle bend
node3 = NodeMV(
    NodeMV.General(name="C", unom=10.0),
    presentations=[NodePresentation(sheet=sheet_guid, x=100, y=200)],
)
node3.register(network)

node4 = NodeMV(
    NodeMV.General(name="D", unom=10.0),
    presentations=[NodePresentation(sheet=sheet_guid, x=300, y=300)],
)
node4.register(network)

link2 = LinkMV(
    LinkMV.General(node1=node3.general.guid, node2=node4.general.guid),
    presentations=[
        BranchPresentation(
            sheet=sheet_guid,
            first_corners=[(100, 200), (100, 250)],
            second_corners=[(300, 300), (300, 250)],
        )
    ],
)
link2.register(network)

network.save("branch_corners.vnf")
logger.info("Branch corner examples saved")