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:
| List | Direction | Description |
|---|---|---|
first_corners | From Node1 outward | Polyline starting at Node1 |
second_corners | From Node2 outward | Polyline 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
first_corners: polyline starting from Node1, traveling outwardsecond_corners: polyline starting from Node2 (not ending!)Example 1: Simple Straight Line
Two nodes at the same Y coordinate with a horizontal connection:
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:
# 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.
first_corners: [(100,200), (100,250)] (down from C)second_corners: [(300,300), (300,250)] (up from D)Example 3: Complex Zig-Zag with Diagonals
Multiple waypoints creating a complex path:
# 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:
Example 4: Minimal Specification
The simplest valid branch uses just the node positions:
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
first_corners=[(x1, y), (midpoint, y)]
second_corners=[(x2, y)]Vertical Connection
first_corners=[(x, y1), (x, midpoint)]
second_corners=[(x, y2)]L-Shape (Right Angle)
# Node1 at (100, 100), Node2 at (300, 200)
first_corners=[(100, 100), (100, 200)] # Down from Node1
second_corners=[(300, 200)] # At Node2Z-Shape
# 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=150Validation
PyPtP validates that corner coordinates align with node positions. See Branch Corner Validation for details on the grid-based tolerance system.
Complete Example
"""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")