Graph-Easy-Introspect
view release on metacpan or search on metacpan
lib/Graph/Easy/Introspect.pm view on Meta::CPAN
line_y1 => 0,
line_x2 => 0,
line_y2 => 0,
type => Graph::Easy::Introspect::cell_type_name($type_base),
type_code => $type_base,
is_label => $is_label,
} ;
}
# Sort path cells into traversal order by adjacency walk from from_port.
# $edge->{cells} is a hash so storage order is undefined.
if (!$is_self_loop && $from_port && @path > 1)
{
my %by_pos = map { my $k = "$_->{x},$_->{y}" ; $k => $_ } @path ;
my $start_key = "$from_port->{x},$from_port->{y}" ;
unless (exists $by_pos{$start_key})
{
for my $d ([-1,0],[1,0],[0,-1],[0,1])
{
my $k = ($from_port->{x}+$d->[0]) . ',' . ($from_port->{y}+$d->[1]) ;
if (exists $by_pos{$k}) { $start_key = $k ; last }
}
}
my @sorted ;
my %visited ;
my $cur = $start_key ;
while (exists $by_pos{$cur} && !$visited{$cur})
{
$visited{$cur} = 1 ;
push @sorted, $by_pos{$cur} ;
my $c = $by_pos{$cur} ;
my $next ;
for my $d ([-1,0],[1,0],[0,-1],[0,1])
{
my $nk = ($c->{x}+$d->[0]) . ',' . ($c->{y}+$d->[1]) ;
next unless exists $by_pos{$nk} && !$visited{$nk} ;
$next = $nk ;
last ;
}
last unless defined $next ;
$cur = $next ;
}
@path = @sorted if @sorted == @path ;
}
# Compute line_* for each path cell using a waypoint-based polyline model.
#
# Waypoints: [from_port_char, corner_0_bend, ..., corner_n_bend, to_port_char]
# Each corner cell either introduces a straight run (next cell is VER/HOR)
# or terminates one (prev cell is VER/HOR).
# Introducing corner: assign wp[ci]->wp[ci+1], then advance ci.
# Terminating corner: advance ci first, then assign wp[ci]->wp[ci+1].
# VER/HOR cells: always assign wp[ci]->wp[ci+1], never advance ci.
#
# This gives contiguous, directed segments: each cell's endpoint equals
# the next cell's start point.
my %is_straight_type = (VER => 1, HOR => 1, CROSS => 1, HOLE => 1) ;
my ($fp_lx, $fp_ly) = (0, 0) ;
my ($tp_lx, $tp_ly) = (0, 0) ;
unless ($is_self_loop)
{
($fp_lx, $fp_ly) = Graph::Easy::Introspect::face_char($from_ast_node, $from_side)
if $from_side ne 'unknown' ;
($tp_lx, $tp_ly) = Graph::Easy::Introspect::face_char($to_ast_node, $to_side)
if $to_side ne 'unknown' ;
}
# Build mid_x/mid_y for each cell (needed for corner bends).
my %cell_mid ;
for my $p (@path)
{
my $cp2 = $char_pos->{"$p->{x},$p->{y}"} // {} ;
my $midx = ($cp2->{char_x} // 0) + int(($cp2->{render_w} // 1) / 2) ;
my $midy = ($cp2->{char_y} // 0) + int(($cp2->{render_h} // 1) / 2) ;
$cell_mid{"$p->{x},$p->{y}"} = [$midx, $midy] ;
}
# Build waypoint list.
my @wp = ([$fp_lx, $fp_ly]) ;
for my $p (@path)
{
next if $is_straight_type{$p->{type}} ;
my $m = $cell_mid{"$p->{x},$p->{y}"} ;
push @wp, [$m->[0], $m->[1]] ;
}
push @wp, [$tp_lx, $tp_ly] ;
# Assign line_* to each cell.
my $ci = 0 ;
for my $i (0 .. $#path)
{
my $p = $path[$i] ;
my $prev = $i > 0 ? $path[$i-1] : undef ;
if ($is_straight_type{$p->{type}})
{
my $next_ci = $ci + 1 < $#wp ? $ci + 1 : $#wp ;
$p->{line_x1} = $wp[$ci][0] ;
$p->{line_y1} = $wp[$ci][1] ;
$p->{line_x2} = $wp[$next_ci][0] ;
$p->{line_y2} = $wp[$next_ci][1] ;
}
else
{
my $prev_straight = $prev && $is_straight_type{$prev->{type}} ;
$ci++ if $prev_straight ;
my $next_ci = $ci + 1 < $#wp ? $ci + 1 : $#wp ;
( run in 0.632 second using v1.01-cache-2.11-cpan-39bf76dae61 )