
/* "WOL", an integrated circuit layout tool,
   Copyright (C) 1983, 1990 California Institute of Technology.
   Author: Massimo Sivilotti
   Thanks to: Glenn Gribble, Marty Sirkin, Sylvie Rychebusch
	      Maryann Mayer, Carver Mead, Rick Koshi, Torre Lande
   Maintainer: John Lazzaro
   Maintainers's address: lazzaro@hobiecat.cs.caltech.edu;
                          CB 425/ CU Boulder/Boulder CO 91125. 
			  Send questions, bug fixes, to this address.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (Version 1, 1989).

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

/* Output from p2c, the Pascal-to-C translator */
/* p2c: wolopt.text, line 9: Note: Range checking is OFF [216] */
/* p2c: wolopt.text, line 10: Note: Stack checking is OFF [217] */
/* p2c: wolopt.text, line 16: Note: Range checking is ON [216] */
/* From input file "wol_route.text" */


/* Change these for testing */



#include "global.h"


#define WOL_ROUTE_G
#include "wol_route.h"


Static boolean point_in(routing *rt, point pt)
{
  boolean temp;

  temp = false;
  if (rt == NULL)
    return temp;
  if (rt->pt1.x == pt.x && rt->pt1.y == pt.y ||
      rt->pt2.x == pt.x && rt->pt2.y == pt.y)
    temp = true;
  else
    temp = point_in(rt->to_point, pt);
  return temp;
}


Local point get_newpoint(point pt, short layer)
{
  /* draws a little line from pt to pen;
     when pen is depressed.  That point is returned. */
  point Result, lam_pt, old_point, screen_start;
  tablet_info tp_d, old_tp_d;

  lam_pt = pt;
  screen_start = scale_up(lam_pt);
  old_point = screen_start;
  old_tp_d.x = INFIN;
  old_tp_d.y = INFIN;
  do {
    tp_d = check_pen();
    tp_d = scale(tp_d, 3);
    if (tp_d.x != old_tp_d.x || tp_d.y != old_tp_d.y) {
      old_tp_d = tp_d;
      xor_on();
      /* next two set_layers used to be set_layer (layer) */
      set_layer(layer);
      m_move(screen_start.x, screen_start.y);   /* erase old wire segment */
      m_draw(old_point.x, old_point.y);
      old_point = scale_up(scale_down(change_to_point(tp_d.x, tp_d.y)));
      set_layer(layer);
      m_move(screen_start.x, screen_start.y);   /* draw new wire segment */
      m_draw(old_point.x, old_point.y);
    }
  } while (!tp_d.depressed);
  Result = scale_down(change_to_point(tp_d.x, tp_d.y));
  /*   set_layer (old_layer);   */
  debounce();
  xor_off();
  return Result;
}

Local boolean point_on_segment(point pt, routing *seg)
{
  boolean Result;

  Result = false;
  if (seg->pt1.x == seg->pt2.x && seg->pt1.x == pt.x &&
      (seg->pt1.y >= pt.y && pt.y >= seg->pt2.y ||
       seg->pt1.y <= pt.y && pt.y <= seg->pt2.y))
    Result = true;
  if (seg->pt1.y == seg->pt2.y && seg->pt1.y == pt.y &&
      (seg->pt1.x >= pt.x && pt.x >= seg->pt2.x ||
       seg->pt1.x <= pt.x && pt.x <= seg->pt2.x))
    return true;
  return Result;
}

Local boolean pt_equals(point pt1, point pt2)
{
  return (pt1.x == pt2.x && pt1.y == pt2.y);
}


void edit_routing_wire(point pt)
{
  point lam_pt, newpoint;
  routing *rt, *seg, *last_seg;
  long layer, old_layer;
  boolean done;

  lam_pt = scale_down(pt);
  rt = comp_cells->routing_;
  if (manhattan_routing) {
    done = false;
    while (rt != NULL && !done) {  /* Search all the wires. */
      if (pt_equals(lam_pt, rt->pt1)) {  /* Special case: end point */
	done = true;
	newpoint = get_newpoint(lam_pt, rt->layer);
	if (rt->pt1.x == rt->pt2.x) {
	  rt->pt2.x = newpoint.x;
	  if (rt->to_point != NULL)
	    rt->to_point->pt1.x = newpoint.x;
	} else if (rt->pt1.y == rt->pt2.y) {
	  rt->pt2.y = newpoint.y;
	  if (rt->to_point != NULL)
	    rt->to_point->pt1.y = newpoint.y;
	}
	rt->pt1 = newpoint;
      } else {
	last_seg = NULL;
	seg = rt;
	while (seg != NULL && !done) {  /* Search the segments. */
	  if (seg->to_point == NULL && pt_equals(lam_pt, seg->pt2))
	  {  /* Special case: end point */
	    done = true;
	    newpoint = get_newpoint(lam_pt, seg->layer);
	    if (seg->pt1.x == seg->pt2.x) {
	      seg->pt1.x = newpoint.x;
	      if (last_seg != NULL)
		last_seg->pt2.x = newpoint.x;
	    } else if (seg->pt1.y == seg->pt2.y) {
	      seg->pt1.y = newpoint.y;
	      if (last_seg != NULL)
		last_seg->pt2.y = newpoint.y;
	    }
	    seg->pt2 = newpoint;
	  } else if (point_on_segment(lam_pt, seg)) {
	    done = true;
	    newpoint = get_newpoint(lam_pt, rt->layer);
	    if (seg->pt1.x == seg->pt2.x) {
	      if (last_seg != NULL)
		last_seg->pt2.x = newpoint.x;
	      seg->pt1.x = newpoint.x;
	      seg->pt2.x = newpoint.x;
	      if (seg->to_point != NULL)
		seg->to_point->pt1.x = newpoint.x;
	    } else if (seg->pt1.y == seg->pt2.y) {
	      if (last_seg != NULL)
		last_seg->pt2.y = newpoint.y;
	      seg->pt1.y = newpoint.y;
	      seg->pt2.y = newpoint.y;
	      if (seg->to_point != NULL)
		seg->to_point->pt1.y = newpoint.y;
	    }
	  }
	  last_seg = seg;
	  seg = seg->to_point;
	}
      }
      rt = rt->next;
    }
    if (done && auto_refresh)
      show_comp();
    return;
  }
  /* Old non-manhattan editing. */
  while (rt != NULL && !point_in(rt, lam_pt))
    rt = rt->next;
  if (!point_in(rt, lam_pt))   /* now go down the wire segment list */
    return;
  old_layer = curr_layer;
  layer = curr_layer;   /* so that the edited line is drawn correctly */
  if (rt->pt1.x == lam_pt.x && rt->pt1.y == lam_pt.y)
  {  /* the point is the first in the line */
    newpoint = get_newpoint(lam_pt, rt->layer);
    rt->pt1 = newpoint;
    if (auto_refresh)
      show_comp();
  } else {
    while (rt->pt2.x != lam_pt.x || rt->pt2.y != lam_pt.y)
	  /* until we find the point */
	    rt = rt->to_point;
    newpoint = get_newpoint(lam_pt, rt->layer);
    if (rt->to_point == NULL) {  /* it is the last point in line */
      rt->pt2 = newpoint;
      if (auto_refresh)
	show_comp();
    } else {  /* update two segments */
      rt->pt2 = newpoint;
      rt->to_point->pt1 = newpoint;
      if (auto_refresh)
	show_comp();
    }
  }
  comp_cells->modified = true;
}


/* Local variables for draw_routing_wire: */
struct LOC_draw_routing_wire {
  point lambda_start;
} ;

Local void new_wire(point endpt, struct LOC_draw_routing_wire *LINK)
{
  /* add a new line segment to the routing list */
  routing *old_rt, *WITH;

  /*     endpt := scale_down (endpt);         */
  old_rt = comp_cells->routing_;
  comp_cells->routing_ = get_routing_node();
  WITH = comp_cells->routing_;
  WITH->pt1 = LINK->lambda_start;
  WITH->pt2 = endpt;
  WITH->layer = curr_layer;
  WITH->width = wire_width;
  WITH->to_point = NULL;
  WITH->next = old_rt;
  comp_cells->modified = true;
}

Local void addline(point endpt, struct LOC_draw_routing_wire *LINK)
{
  /* add a new segment to the wire hanging off of comp_cells^.data^.routing */
  routing *rt, *WITH;

  /* endpt := scale_down (endpt);   */
  rt = comp_cells->routing_;
  while (rt->to_point != NULL)
    rt = rt->to_point;
  rt->to_point = get_routing_node();
  WITH = rt->to_point;
  WITH->pt1 = LINK->lambda_start;
  WITH->pt2 = endpt;
  WITH->layer = curr_layer;
  WITH->width = wire_width;
  WITH->to_point = NULL;
  WITH->next = NULL;
  comp_cells->modified = true;
}


/*******************************************************************************/

void draw_routing_wire(point start)
{
  struct LOC_draw_routing_wire V;
  point lambda_old_point, old_point, screen_start, tp_lam;
  tablet_info tp_d, old_tp_d;
  boolean first_segment;

  V.lambda_start = scale_down(start);
  lambda_old_point = V.lambda_start;
  screen_start = scale_up(V.lambda_start);
  old_point = screen_start;
  first_segment = true;
  old_tp_d.x = INFIN;
  old_tp_d.y = INFIN;
  /*   writeln ('wire started: ',lambda_start.x:1,' ', lambda_start.y:1);  */
  do {
    tp_d = check_pen();
    screen_start = scale_up(V.lambda_start);
    /*$if false$
      if manhattan_routing then
         begin
          if (abs (tp_d.x - screen_start.x) -
              abs(tp_d.y - screen_start.y)) > 0 then
                 { preserve y-coord }
                   tp_d.y := screen_start.y
                 else { preserve x-coord }
                   tp_d.x := screen_start.x;
         end;
      tp_d := scale(tp_d,3);
$end$*/
    tp_lam = scale_down(change_to_point(tp_d.x, tp_d.y));
    tp_d.x = scale_up(tp_lam).x;
    tp_d.y = scale_up(tp_lam).y;
    if (manhattan_routing) {
      if (labs(tp_d.x - screen_start.x) - labs(tp_d.y - screen_start.y) > 0) {
	/* preserve y-coord */
	tp_d.y = screen_start.y;
      } else  /* preserve x-coord */
	tp_d.x = screen_start.x;
    }

    if (tp_d.x != old_tp_d.x || tp_d.y != old_tp_d.y) {
      xor_on();
      set_layer(curr_layer);
      screen_start = scale_up(V.lambda_start);
      m_move(screen_start.x, screen_start.y);   /* erase old wire segment */
      old_point = scale_up(lambda_old_point);
      m_draw(old_point.x, old_point.y);
      lambda_old_point = scale_down(change_to_point(tp_d.x, tp_d.y));

      /*   writeln ('Pen pos: ',lambda_old_point.x:1,' ', lambda_old_point.y:1);  */
      old_point = scale_up(lambda_old_point);
      old_tp_d = tp_d;
      set_layer(curr_layer);
      m_move(screen_start.x, screen_start.y);   /* draw new wire segment */
      m_draw(old_point.x, old_point.y);
    }
    if (tp_d.depressed) {
      /* tp_d now in lambda coordinates */
      tp_d.x = scale_down(change_to_point(tp_d.x, tp_d.y)).x;
      tp_d.y = scale_down(change_to_point(tp_d.x, tp_d.y)).y;
      if (manhattan_routing) {
	if (labs(tp_d.x - V.lambda_start.x) - labs(tp_d.y - V.lambda_start.y) > 0) {
	  /* preserve y-coord */
	  tp_d.y = V.lambda_start.y;
	} else  /* preserve x-coord */
	  tp_d.x = V.lambda_start.x;
      }
      if (first_segment) {
	new_wire(change_to_point(tp_d.x, tp_d.y), &V);
	first_segment = false;
      } else
	addline(change_to_point(tp_d.x, tp_d.y), &V);
      V.lambda_start = change_to_point(tp_d.x, tp_d.y);
      lambda_old_point = V.lambda_start;
      screen_start = scale_up(V.lambda_start);
      old_point = screen_start;
      debounce();
    }
  } while (tp_d.near_);
  if (!tp_d.near_) {
    xor_on();
    set_layer(curr_layer);
    screen_start = scale_up(V.lambda_start);
    m_move(screen_start.x, screen_start.y);
    old_point = scale_up(lambda_old_point);
    m_draw(old_point.x, old_point.y);
  }
  xor_off();
}


/*******************************************************************************/


void delete_routing_wire(point pt)
{
  /* searches all wires to find one that ends on the specified point,
     then deletes all segments that belong to it */
  routing *rt, *rt2;
  boolean done;

  rt = comp_cells->routing_;   /* rt runs down segment lists */
  rt2 = rt;   /* rt2 points one back from rt */
  pt = scale_down(pt);
  if (point_in(rt, pt)) {  /* segment is in first wire */
    comp_cells->routing_ = comp_cells->routing_->next;
    recl_routing_node(&rt);
    comp_cells->modified = true;
    if (auto_refresh)   /* refresh the screen */
      show_comp();
    return;
  }
  done = false;
  rt = rt->next;
  while (rt != NULL && !done) {
    if (!point_in(rt, pt)) {
      rt2 = rt;
      rt = rt->next;
      continue;
    }
    rt2->next = rt->next;
    recl_routing_node(&rt);
    comp_cells->modified = true;
    if (auto_refresh)   /* refresh the screen */
      show_comp();
    done = true;
  }

  /* segment may be in subsequent wire */
  /* consider next wire */
}


/*******************************************************************************/

/*$if false$  pending correction by John T
PROCEDURE edit_routing_wire (pt : point);
var lambda_start, newpoint : point;
    rt : routing_ptr;
    layer, old_layer : integer;

    function get_newpoint (pt : point) : point;
    { draws a little line from pt to pen;
      when pen is depressed, that point is returned }
    var lambda_start, old_point, screen_start : point;
        tp_d, old_tp_d : tablet_info;
    begin
       lambda_start := pt;
       screen_start := scale_up (lambda_start);
       old_point := screen_start;
       old_tp_d.x := INFIN;
       old_tp_d.y := INFIN;
       repeat
         tp_d := check_pen;
         tp_d := scale(tp_d,3);
         if (tp_d.x <> old_tp_d.x) or (tp_d.y <> old_tp_d.y) then
           begin
              old_tp_d := tp_d;
              xor_on;
              { next two set_layers used to be set_layer (layer) }
              set_layer (BR_WHITE);
              m_move (screen_start.x, screen_start.y);    { erase old wire segment }
              m_draw (old_point.x, old_point.y);
              old_point := scale_up (scale_down (change_to_point (tp_d.x, tp_d.y)));
              set_layer (BR_WHITE);
              m_move (screen_start.x, screen_start.y);    { draw new wire segment }
              m_draw (old_point.x, old_point.y);
           end;
       until tp_d.depressed;
       get_newpoint := scale_down (change_to_point (tp_d.x, tp_d.y));
       set_layer (old_layer);
       debounce;
       xor_off;
    end;

begin
   lambda_start := scale_down (pt);
   rt := comp_cells^.routing;
   while (rt <> nil) and not point_in (rt, lambda_start)
     do rt := rt^.next;
   if point_in (rt, lambda_start) then  { now go down the wire segment list }
     begin
       old_layer := curr_layer;
       layer := curr_layer; { so that the edited line is drawn correctly }
       if (rt^.pt1.x = lambda_start.x) and (rt^.pt1.y = lambda_start.y) then
         begin  { the point is the first in the line }
           newpoint := get_newpoint (lambda_start);
           rt^.pt1 := newpoint;
           if auto_refresh then show_comp;
         end
       else begin
              while (rt^.pt2.x <> lambda_start.x) or
                    (rt^.pt2.y <> lambda_start.y) do
                 rt := rt^.to_point;  { until we find the point }
              newpoint := get_newpoint (lambda_start);
              if rt^.to_point = nil then
                begin  { it is the last point in line }
                  rt^.pt2 := newpoint;
                  if auto_refresh then show_comp;
                end
              else begin { update two segments }
                     rt^.pt2 := newpoint;
                     rt^.to_point^.pt1 := newpoint;
                     if auto_refresh then show_comp;
                   end;
            end;
       comp_cells^.modified := true;
     end;
end;
$end$*/
/*******************************************************************************/
/* module wol_route*/



/* End. */
