Example #1
0
/*
 * Find the bounding box of a POLYAREA
 * POLYAREAs linked by ->f/b are outlines.  n->contours->next would
 * be the start of the inner holes (irrelevant for bounding box)
 */
static BoxType
POLYAREA_boundingBox(POLYAREA *a)
{
	POLYAREA *n;
	PLINE *pa;
	BoxType box;
	int first = 1;

	n = a;
	do {
		pa = n->contours;
		if (first) {
			box.X1 = pa->xmin;
			box.X2 = pa->xmax + 1;
			box.Y1 = pa->ymin;
			box.Y2 = pa->ymax + 1;
			first = 0;
		} else {
			MAKEMIN(box.X1, pa->xmin);
			MAKEMAX(box.X2, pa->xmax + 1);
			MAKEMIN(box.Y1, pa->ymin);
			MAKEMAX(box.Y2, pa->ymax + 1);
		}
	} while ((n = n->f) != a);
	return box;
}
Example #2
0
/*!
 * \brief Set the node bounds large enough to encompass all of the
 * children's rectangles.
 */
static void
adjust_bounds (struct rtree_node *node)
{
  int i;

  assert (node);
  assert (node->u.kids[0]);
  if (node->flags.is_leaf)
    {
      node->box = node->u.rects[0].bounds;
      for (i = 1; i < M_SIZE + 1; i++)
        {
          if (!node->u.rects[i].bptr)
            return;
          MAKEMIN (node->box.X1, node->u.rects[i].bounds.X1);
          MAKEMAX (node->box.X2, node->u.rects[i].bounds.X2);
          MAKEMIN (node->box.Y1, node->u.rects[i].bounds.Y1);
          MAKEMAX (node->box.Y2, node->u.rects[i].bounds.Y2);
        }
    }
  else
    {
      node->box = node->u.kids[0]->box;
      for (i = 1; i < M_SIZE + 1; i++)
        {
          if (!node->u.kids[i])
            return;
          MAKEMIN (node->box.X1, node->u.kids[i]->box.X1);
          MAKEMAX (node->box.X2, node->u.kids[i]->box.X2);
          MAKEMIN (node->box.Y1, node->u.kids[i]->box.Y1);
          MAKEMAX (node->box.Y2, node->u.kids[i]->box.Y2);
        }
    }
}
Example #3
0
/* ---------------------------------------------------------------------------
 * Compute cost function.
 *  note that area overlap cost is correct for SMD devices: SMD devices on
 *  opposite sides of the board don't overlap.
 *
 * Algorithms follow those described in sections 4.1 of
 *  "Placement and Routing of Electronic Modules" edited by Michael Pecht
 *  Marcel Dekker, Inc. 1993.  ISBN: 0-8247-8916-4 TK7868.P7.P57 1993
 */
static double
ComputeCost (NetListTypePtr Nets, double T0, double T)
{
  double W = 0;			/* wire cost */
  double delta1 = 0;		/* wire congestion penalty function */
  double delta2 = 0;		/* module overlap penalty function */
  double delta3 = 0;		/* out of bounds penalty */
  double delta4 = 0;		/* alignment bonus */
  double delta5 = 0;		/* total area penalty */
  Cardinal i, j;
  LocationType minx, maxx, miny, maxy;
  bool allpads, allsameside;
  Cardinal thegroup;
  BoxListType bounds = { 0, 0, NULL };	/* save bounding rectangles here */
  BoxListType solderside = { 0, 0, NULL };	/* solder side component bounds */
  BoxListType componentside = { 0, 0, NULL };	/* component side bounds */
  /* make sure the NetList have the proper updated X and Y coords */
  UpdateXY (Nets);
  /* wire length term.  approximated by half-perimeter of minimum
   * rectangle enclosing the net.  Note that we penalize vias in
   * all-SMD nets by making the rectangle a cube and weighting
   * the "layer height" of the net. */
  for (i = 0; i < Nets->NetN; i++)
    {
      NetTypePtr n = &Nets->Net[i];
      if (n->ConnectionN < 2)
	continue;		/* no cost to go nowhere */
      minx = maxx = n->Connection[0].X;
      miny = maxy = n->Connection[0].Y;
      thegroup = n->Connection[0].group;
      allpads = (n->Connection[0].type == PAD_TYPE);
      allsameside = true;
      for (j = 1; j < n->ConnectionN; j++)
	{
	  ConnectionTypePtr c = &(n->Connection[j]);
	  MAKEMIN (minx, c->X);
	  MAKEMAX (maxx, c->X);
	  MAKEMIN (miny, c->Y);
	  MAKEMAX (maxy, c->Y);
	  if (c->type != PAD_TYPE)
	    allpads = false;
	  if (c->group != thegroup)
	    allsameside = false;
	}
      /* save bounding rectangle */
      {
	BoxTypePtr box = GetBoxMemory (&bounds);
	box->X1 = minx;
	box->Y1 = miny;
	box->X2 = maxx;
	box->Y2 = maxy;
      }
      /* okay, add half-perimeter to cost! */
      W += (maxx - minx) / 100 + (maxy - miny) / 100 +
	((allpads && !allsameside) ? CostParameter.via_cost : 0);
    }
  /* now compute penalty function Wc which is proportional to
   * amount of overlap and congestion. */
  /* delta1 is congestion penalty function */
  delta1 = CostParameter.congestion_penalty *
    sqrt (fabs (ComputeIntersectionArea (&bounds)));
#if 0
  printf ("Wire Congestion Area: %f\n", ComputeIntersectionArea (&bounds));
#endif
  /* free bounding rectangles */
  FreeBoxListMemory (&bounds);
  /* now collect module areas (bounding rect of pins/pads) */
  /* two lists for solder side / component side. */

  ELEMENT_LOOP (PCB->Data);
  {
    BoxListTypePtr thisside;
    BoxListTypePtr otherside;
    BoxTypePtr box;
    BoxTypePtr lastbox = NULL;
    BDimension thickness;
    BDimension clearance;
    if (TEST_FLAG (ONSOLDERFLAG, element))
      {
	thisside = &solderside;
	otherside = &componentside;
      }
    else
      {
	thisside = &componentside;
	otherside = &solderside;
      }
    box = GetBoxMemory (thisside);
    /* protect against elements with no pins/pads */
    if (element->PinN == 0 && element->PadN == 0)
      continue;
    /* initialize box so that it will take the dimensions of
     * the first pin/pad */
    box->X1 = MAX_COORD;
    box->Y1 = MAX_COORD;
    box->X2 = -MAX_COORD;
    box->Y2 = -MAX_COORD;
    PIN_LOOP (element);
    {
      thickness = pin->Thickness / 2;
      clearance = pin->Clearance * 2;
    EXPANDRECTXY (box,
		    pin->X - (thickness + clearance),
		    pin->Y - (thickness + clearance),
		    pin->X + (thickness + clearance),
		    pin->Y + (thickness + clearance))}
    END_LOOP;
    PAD_LOOP (element);
    {
      thickness = pad->Thickness / 2;
      clearance = pad->Clearance * 2;
    EXPANDRECTXY (box,
		    MIN (pad->Point1.X,
			   pad->Point2.X) - (thickness +
					       clearance),
		    MIN (pad->Point1.Y,
			   pad->Point2.Y) - (thickness +
					       clearance),
		    MAX (pad->Point1.X,
			   pad->Point2.X) + (thickness +
					       clearance),
		    MAX (pad->Point1.Y,
			   pad->Point2.Y) + (thickness + clearance))}
    END_LOOP;
    /* add a box for each pin to the "opposite side":
     * surface mount components can't sit on top of pins */
    if (!CostParameter.fast)
      PIN_LOOP (element);
    {
      box = GetBoxMemory (otherside);
      thickness = pin->Thickness / 2;
      clearance = pin->Clearance * 2;
      /* we ignore clearance here */
      /* (otherwise pins don't fit next to each other) */
      box->X1 = pin->X - thickness;
      box->Y1 = pin->Y - thickness;
      box->X2 = pin->X + thickness;
      box->Y2 = pin->Y + thickness;
      /* speed hack! coalesce with last box if we can */
      if (lastbox != NULL &&
	  ((lastbox->X1 == box->X1 &&
	    lastbox->X2 == box->X2 &&
	    MIN (abs (lastbox->Y1 - box->Y2),
		 abs (box->Y1 - lastbox->Y2)) <
	    clearance) || (lastbox->Y1 == box->Y1
			   && lastbox->Y2 == box->Y2
			   &&
			   MIN (abs
				(lastbox->X1 -
				 box->X2),
				abs (box->X1 - lastbox->X2)) < clearance)))
	{
	  EXPANDRECT (lastbox, box);
	  otherside->BoxN--;
	}
      else
	lastbox = box;
    }
    END_LOOP;
    /* assess out of bounds penalty */
    if (element->VBox.X1 < 0 ||
	element->VBox.Y1 < 0 ||
	element->VBox.X2 > PCB->MaxWidth || element->VBox.Y2 > PCB->MaxHeight)
      delta3 += CostParameter.out_of_bounds_penalty;
  }
  END_LOOP;
  /* compute intersection area of module areas box list */
  delta2 = sqrt (fabs (ComputeIntersectionArea (&solderside) +
		       ComputeIntersectionArea (&componentside))) *
    (CostParameter.overlap_penalty_min +
     (1 - (T / T0)) * CostParameter.overlap_penalty_max);
#if 0
  printf ("Module Overlap Area (solder): %f\n",
	  ComputeIntersectionArea (&solderside));
  printf ("Module Overlap Area (component): %f\n",
	  ComputeIntersectionArea (&componentside));
#endif
  FreeBoxListMemory (&solderside);
  FreeBoxListMemory (&componentside);
  /* reward pin/pad x/y alignment */
  /* score higher if pins/pads belong to same *type* of component */
  /* XXX: subkey should be *distance* from thing aligned with, so that
   * aligning to something far away isn't profitable */
  {
    /* create r tree */
    PointerListType seboxes = { 0, 0, NULL }
    , ceboxes =
    {
    0, 0, NULL};
    struct ebox
    {
      BoxType box;
      ElementTypePtr element;
    };
    direction_t dir[4] = { NORTH, EAST, SOUTH, WEST };
    struct ebox **boxpp, *boxp;
    rtree_t *rt_s, *rt_c;
    int factor;
    ELEMENT_LOOP (PCB->Data);
    {
      boxpp = (struct ebox **)
	GetPointerMemory (TEST_FLAG (ONSOLDERFLAG, element) ?
			  &seboxes : &ceboxes);
      *boxpp = malloc (sizeof (**boxpp));
      if (*boxpp == NULL ) 
	{
	  fprintf (stderr, "malloc() failed in %s\n", __FUNCTION__);
	  exit (1);
	}

      (*boxpp)->box = element->VBox;
      (*boxpp)->element = element;
    }
    END_LOOP;
    rt_s = r_create_tree ((const BoxType **) seboxes.Ptr, seboxes.PtrN, 1);
    rt_c = r_create_tree ((const BoxType **) ceboxes.Ptr, ceboxes.PtrN, 1);
    FreePointerListMemory (&seboxes);
    FreePointerListMemory (&ceboxes);
    /* now, for each element, find its neighbor on all four sides */
    delta4 = 0;
    for (i = 0; i < 4; i++)
      ELEMENT_LOOP (PCB->Data);
    {
      boxp = (struct ebox *)
	r_find_neighbor (TEST_FLAG (ONSOLDERFLAG, element) ?
			 rt_s : rt_c, &element->VBox, dir[i]);
      /* score bounding box alignments */
      if (!boxp)
	continue;
      factor = 1;
      if (element->Name[0].TextString &&
	  boxp->element->Name[0].TextString &&
	  0 == NSTRCMP (element->Name[0].TextString,
			boxp->element->Name[0].TextString))
	{
	  delta4 += CostParameter.matching_neighbor_bonus;
	  factor++;
	}
      if (element->Name[0].Direction == boxp->element->Name[0].Direction)
	delta4 += factor * CostParameter.oriented_neighbor_bonus;
      if (element->VBox.X1 ==
	  boxp->element->VBox.X1 ||
	  element->VBox.X1 ==
	  boxp->element->VBox.X2 ||
	  element->VBox.X2 ==
	  boxp->element->VBox.X1 ||
	  element->VBox.X2 ==
	  boxp->element->VBox.X2 ||
	  element->VBox.Y1 ==
	  boxp->element->VBox.Y1 ||
	  element->VBox.Y1 ==
	  boxp->element->VBox.Y2 ||
	  element->VBox.Y2 ==
	  boxp->element->VBox.Y1 ||
	  element->VBox.Y2 == boxp->element->VBox.Y2)
	delta4 += factor * CostParameter.aligned_neighbor_bonus;
    }
    END_LOOP;
    /* free k-d tree memory */
    r_destroy_tree (&rt_s);
    r_destroy_tree (&rt_c);
  }
  /* penalize total area used by this layout */
  {
    LocationType minX = MAX_COORD, minY = MAX_COORD;
    LocationType maxX = -MAX_COORD, maxY = -MAX_COORD;
    ELEMENT_LOOP (PCB->Data);
    {
      MAKEMIN (minX, element->VBox.X1);
      MAKEMIN (minY, element->VBox.Y1);
      MAKEMAX (maxX, element->VBox.X2);
      MAKEMAX (maxY, element->VBox.Y2);
    }
    END_LOOP;
    if (minX < maxX && minY < maxY)
      delta5 = CostParameter.overall_area_penalty *
	sqrt ((double) (maxX - minX) * (maxY - minY) * 0.0001);
  }
  if (T == 5)
    {
      T = W + delta1 + delta2 + delta3 - delta4 + delta5;
      printf ("cost components are %.3f %.3f %.3f %.3f %.3f %.3f\n",
	      W / T, delta1 / T, delta2 / T, delta3 / T, -delta4 / T,
	      delta5 / T);
    }
  /* done! */
  return W + (delta1 + delta2 + delta3 - delta4 + delta5);
}
Example #4
0
static void
__r_insert_node (struct rtree_node *node, const BoxType * query,
                 int manage, bool force)
{

#ifdef SLOW_ASSERTS
  assert (__r_node_is_good (node));
#endif
  /* Ok, at this point we must already enclose the query or we're forcing
   * this node to expand to enclose it, so if we're a leaf, simply store
   * the query here
   */

  if (node->flags.is_leaf)
    {
      register int i;

      if (UNLIKELY (manage))
        {
          register int flag = 1;

          for (i = 0; i < M_SIZE; i++)
            {
              if (!node->u.rects[i].bptr)
                break;
              flag <<= 1;
            }
          node->flags.manage |= flag;
        }
      else
        {
          for (i = 0; i < M_SIZE; i++)
            if (!node->u.rects[i].bptr)
              break;
        }
      /* the node always has an extra space available */
      node->u.rects[i].bptr = query;
      node->u.rects[i].bounds = *query;
      /* first entry in node determines initial bounding box */
      if (i == 0)
        node->box = *query;
      else if (force)
        {
          MAKEMIN (node->box.X1, query->X1);
          MAKEMAX (node->box.X2, query->X2);
          MAKEMIN (node->box.Y1, query->Y1);
          MAKEMAX (node->box.Y2, query->Y2);
        }
      if (i < M_SIZE)
        {
          sort_node (node);
          return;
        }
      /* we must split the node */
      split_node (node);
      return;
    }
  else
    {
      int i;
      struct rtree_node *best_node;
      double score, best_score;

      if (force)
        {
          MAKEMIN (node->box.X1, query->X1);
          MAKEMAX (node->box.X2, query->X2);
          MAKEMIN (node->box.Y1, query->Y1);
          MAKEMAX (node->box.Y2, query->Y2);
        }

      /* this node encloses it, but it's not a leaf, so descend the tree */

      /* First check if any children actually encloses it */
      assert (node->u.kids[0]);
      for (i = 0; i < M_SIZE; i++)
        {
          if (!node->u.kids[i])
            break;
          if (contained (node->u.kids[i], query))
            {
              __r_insert_node (node->u.kids[i], query, manage, false);
              sort_node (node);
              return;
            }
        }

      /* see if there is room for a new leaf node */
      if (node->u.kids[0]->flags.is_leaf && i < M_SIZE)
        {
          struct rtree_node *new_node;
          new_node = (struct rtree_node *)calloc (1, sizeof (*new_node));
          new_node->parent = node;
          new_node->flags.is_leaf = true;
          node->u.kids[i] = new_node;
          new_node->u.rects[0].bptr = query;
          new_node->u.rects[0].bounds = *query;
          new_node->box = *query;
          if (UNLIKELY (manage))
            new_node->flags.manage = 1;
          sort_node (node);
          return;
        }

      /* Ok, so we're still here - look for the best child to push it into */
      best_score = penalty (node->u.kids[0], query);
      best_node = node->u.kids[0];
      for (i = 1; i < M_SIZE; i++)
        {
          if (!node->u.kids[i])
            break;
          score = penalty (node->u.kids[i], query);
          if (score < best_score)
            {
              best_score = score;
              best_node = node->u.kids[i];
            }
        }
      __r_insert_node (best_node, query, manage, true);
      sort_node (node);
      return;
    }
}