## -*-octave-*-

function [bonds] = ...
      rbg2ibg(name,rbonds,rstrokes,rcomponents,port_coord,port_name, ...
	      infofile, errorfile)

  rbonds
  rstrokes
  rcomponents
  port_coord
  port_name

  ## Default to no components
  components = [0];

  ## Xfig scaling factor
  scale = 1200.0/2.54546;

  ## Rotation matrix
  rot = [0, -1; 1, 0];

  ## Find number of strokes
  [n_strokes,columns] = size(rstrokes);
  if ((columns ~= 4) & (n_strokes > 0))
    error('Incorrect rstrokes matrix: must have 4 columns');
  endif

  ## Find number of bonds
  [n_bonds,columns] = size(rbonds);
  if ((columns ~= 6) & (n_bonds > 0))
    error('Incorrect rbonds matrix: must have 6 columns');
  endif

  ## Find number of components
  [n_components,columns] = size(rcomponents);

  ## Find number of ports referred to
  [n_ports,columns] = size(port_coord);
  
  ## If port_name empty, make it empty string
  if (length(port_name) == 0)
    port_name="";
  endif
  
  ## Determine coordinates of arrow end of bond and other end
  other_end_1	= rbonds(:,1:2);
  arrow_end	= rbonds(:,3:4);
  other_end_2	= rbonds(:,5:6);

  distance_1	= length2d(other_end_1 - arrow_end);
  distance_2	= length2d(other_end_2 - arrow_end);
  which_end	= (distance_1 > distance_2) * [1, 1];
  one		= ones(size(which_end));
  other_end	= which_end .* other_end_1 + (one - which_end) .* ...
      other_end_2;
  arrow_vector	= (which_end .* other_end_2 + (one - which_end) .* ...
		   other_end_1) - arrow_end;
  
  ## Locate bond end nearest each port
  ## col 1 of port_near_bond contains a signed bond number (+ for arrow
  ## end)
  ## col 2 of port_near_bond contains the corresponding port index
  port_bond = [];
  for i = 1:n_ports
    near_bond = adjbond(port_coord(i,1:2), arrow_end, other_end);
    [rows,cols] = size(near_bond);
    if (rows > 1)
      error(sprintf ...
	    ("A port is near to more than one bond at coordinates ...
	  %g,%g %s\n", ...
	     port_coord(i,1)/scale, port_coord(i,2)/scale, ...
	     deblank(port_name(i,:))));
    endif
    
    ## The (signed) bond corresponding to the ith port label
    port_bond(i,1) = near_bond(1) * sign(1.5 - near_bond(2));
  endfor
  port_bond

  ## Now have (signed) bond (port_bond(i)) corresponding to the ith port
  ## Create inverse mapping
  for i = 1:n_bonds
    eval(sprintf('bond_port_head%i = "[]"', i))
    eval(sprintf('bond_port_tail%i = "[]"', i))
  endfor  
  for i = 1:n_ports
    if (port_bond(i) > 0)
      eval(sprintf('bond_port_head%i = "%s"', port_bond(i), ...
		   deblank(port_name(i,:))))
    else
      eval(sprintf('bond_port_tail%i = "%s"', -port_bond(i), ...
		   deblank(port_name(i,:))))
    endif
  endfor
  
  ## Locate the components at the ends of each bond
  ## col 1 of comp_near_bond contains component nearest to the arrow end
  ## col 2 of comp_near_bond contains component nearest other end
  for i = 1:n_bonds
    comp_near_bond(i,:) = adjcomp(arrow_end(i,:), other_end(i,:), ...
				  rcomponents);
  endfor
  comp_near_bond

  ## Deduce causality from the strokes (if any)
  causality = zeros(n_bonds,2);
  if (n_strokes > 0)
    ## Find location of centre and ends of stroke
    stroke_end_1	= [rstrokes(:,1), rstrokes(:,2)];
    stroke_end_2	= [rstrokes(:,3), rstrokes(:,4)];

    stroke_centre	= (stroke_end_1 + stroke_end_2)/2;
    stroke_vector	= (stroke_end_1 - stroke_end_2);
    stroke_length	= length2d(stroke_vector);

    for i = 1:n_strokes
      stroke = [stroke_centre(i,:)
		stroke_end_1(i,:)
		stroke_end_2(i,:)];


      ## Find the nearest bond end
      [index,distance] = adjbond(stroke(1,:),arrow_end,other_end);
      if (distance > (2 * stroke_length(i)))
	info = sprintf('Stroke at (%4.3f,%4.3f) is %4.3f away from the nearest bond\n', ...
		       stroke(1,1)/scale, stroke(1,2)/scale, ...
		       distance/scale);
      endif

      ## Bond end coordinates
      j = index(1,1);
      which_end = (index(1,2) == 1);
      bond_end = arrow_end(j,:) * which_end + other_end(j,:) * (1 - ...
								which_end);
      
      ## Now decide which bit of the stroke is nearest
      stroke_index = adjbond(bond_end, stroke, zeros(size(stroke)));

      if (stroke_index(1) == 1)	# uni-causal stroke
	causality(j,1:2) = (2 * which_end - 1) * [1, 1];
      else			# bi-causal stroke
	stroke_direction = stroke(1,:) - stroke(stroke_index(1),:);
	flow_side = stroke_direction * arrow_vector(j,:)' > 0;
	causality(j,1+flow_side) = 2 * which_end - 1;
      endif
    endfor
  endif
  causality

  ## Write data
  for i = 1:n_bonds
    [hc_type, hc_name] = eval([name, '_cmp(comp_near_bond(i,1))']);
    [tc_type, tc_name] = eval([name, '_cmp(comp_near_bond(i,2))']);
    ## components
    eval(sprintf("bonds.bond%i.head.component\t= '%s:%s'", i, hc_type, ...
		 hc_name));
    eval(sprintf("bonds.bond%i.tail.component\t= '%s:%s'", i, tc_type, ...
		 tc_name));
    ## ports
    eval(sprintf("bonds.bond%i.head.ports\t= bond_port_head%i", i, i));
    eval(sprintf("bonds.bond%i.tail.ports\t= bond_port_tail%i", i, i));
    ## causality
    if (causality(i,1) == 1)
      effort_causality = "head"
    elseif (causality(i,1) == -1)
      effort_causality = "tail"
    else
      effort_causality = "none"
    endif

    if (causality(i,2) == 1)
      flow_causality = "tail"
    elseif (causality(i,2) == -1)
      flow_causality = "head"
    else
      flow_causality = "none"
    endif
    
    eval(sprintf("bonds.bond%i.causality.effort\t= '%s'", i, effort_causality));
    eval(sprintf("bonds.bond%i.causality.flow\t= '%s'", i, flow_causality));
  endfor

endfunction