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 )