Ejemplo n.º 1
0
/* ---------------------------------------------------------------------------
 * get next slot for a pin, allocates memory if necessary
 */
PinTypePtr
GetPinMemory (ElementTypePtr Element)
{
  PinTypePtr pin = Element->Pin;
  bool onBoard = false;

  /* realloc new memory if necessary and clear it */
  if (Element->PinN >= Element->PinMax)
    {
      if (PCB->Data->pin_tree)
	{
	  PIN_LOOP (Element);
	  {
	    if (r_delete_entry (PCB->Data->pin_tree, (BoxType *) pin))
	      onBoard = true;
	  }
	  END_LOOP;
	}
      Element->PinMax += STEP_PIN;
      pin = MyRealloc (pin, Element->PinMax * sizeof (PinType),
		       "GetPinMemory()");
      Element->Pin = pin;
      memset (pin + Element->PinN, 0, STEP_PIN * sizeof (PinType));
      if (onBoard)
	{
	  PIN_LOOP (Element);
	  {
	    r_insert_entry (PCB->Data->pin_tree, (BoxType *) pin, 0);
	  }
	  END_LOOP;
	}
    }
  return (pin + Element->PinN++);
}
Ejemplo n.º 2
0
/* ---------------------------------------------------------------------------
 * frees memory used by an element
 */
void
FreeElementMemory (ElementTypePtr Element)
{
  if (Element)
    {
      ELEMENTNAME_LOOP (Element);
      {
	MYFREE (textstring);
      }
      END_LOOP;
      PIN_LOOP (Element);
      {
	MYFREE (pin->Name);
	MYFREE (pin->Number);
      }
      END_LOOP;
      PAD_LOOP (Element);
      {
	MYFREE (pad->Name);
	MYFREE (pad->Number);
      }
      END_LOOP;
      MYFREE (Element->Pin);
      MYFREE (Element->Pad);
      MYFREE (Element->Line);
      MYFREE (Element->Arc);
      FreeAttributeListMemory (&Element->Attributes);
      memset (Element, 0, sizeof (ElementType));
    }
}
Ejemplo n.º 3
0
/* ---------------------------------------------------------------------------
 * frees memory used by an element
 */
void
FreeElementMemory (ElementType *element)
{
  if (element == NULL)
    return;

  ELEMENTNAME_LOOP (element);
  {
    free (textstring);
  }
  END_LOOP;
  PIN_LOOP (element);
  {
    free (pin->Name);
    free (pin->Number);
  }
  END_LOOP;
  PAD_LOOP (element);
  {
    free (pad->Name);
    free (pad->Number);
  }
  END_LOOP;

  g_list_free_full (element->Pin,  (GDestroyNotify)FreePin);
  g_list_free_full (element->Pad,  (GDestroyNotify)FreePad);
  g_list_free_full (element->Line, (GDestroyNotify)FreeLine);
  g_list_free_full (element->Arc,  (GDestroyNotify)FreeArc);

  FreeAttributeListMemory (&element->Attributes);
  memset (element, 0, sizeof (ElementType));
}
Ejemplo n.º 4
0
void
log_element(ElementType *e)
{
  base_log("Element\n");
  base_log("Description: %s\n", DESCRIPTION_NAME(e));
  base_log("Name on PCB: %s\n", NAMEONPCB_NAME(e));
  base_log("Value: %s\n", VALUE_NAME(e));
  base_log("Flags: %04x\n", FLAG_VALUE(e->Flags));
  base_log("MarkX, MarkY: %d, %d\n", e->MarkX, e->MarkY);
  base_log("PinN: %d\n", e->PinN);
  base_log("PadN: %d\n", e->PadN);
  base_log("LineN: %d\n", e->LineN);
  base_log("ArcN: %d\n", e->ArcN);
  base_log("Attributes number: %d\n", e->Attributes.Number);

  int i = 0;
  PAD_LOOP(e);
  {
    base_log("Pad %d\n", i++);
    log_pad(pad);
  }
  END_LOOP;

  i = 0;
  PIN_LOOP(e);
  {
    base_log("Pin %d\n", i++);
    log_pin(pin);
  }
  END_LOOP;
}
Ejemplo n.º 5
0
void
FreeRotateElementLowLevel (DataType *Data, ElementType *Element,
			   Coord X, Coord Y,
			   double cosa, double sina, Angle angle)
{
  /* solder side objects need a different orientation */

  /* the text subroutine decides by itself if the direction
   * is to be corrected
   */
#if 0
  ELEMENTTEXT_LOOP (Element);
  {
    if (Data && Data->name_tree[n])
      r_delete_entry (Data->name_tree[n], (BoxType *)text);
    RotateTextLowLevel (text, X, Y, Number);
  }
  END_LOOP;
#endif
  ELEMENTLINE_LOOP (Element);
  {
    free_rotate (&line->Point1.X, &line->Point1.Y, X, Y, cosa, sina);
    free_rotate (&line->Point2.X, &line->Point2.Y, X, Y, cosa, sina);
    SetLineBoundingBox (line);
  }
  END_LOOP;
  PIN_LOOP (Element);
  {
    /* pre-delete the pins from the pin-tree before their coordinates change */
    if (Data)
      r_delete_entry (Data->pin_tree, (BoxType *)pin);
    RestoreToPolygon (Data, PIN_TYPE, Element, pin);
    free_rotate (&pin->X, &pin->Y, X, Y, cosa, sina);
    SetPinBoundingBox (pin);
  }
  END_LOOP;
  PAD_LOOP (Element);
  {
    /* pre-delete the pads before their coordinates change */
    if (Data)
      r_delete_entry (Data->pad_tree, (BoxType *)pad);
    RestoreToPolygon (Data, PAD_TYPE, Element, pad);
    free_rotate (&pad->Point1.X, &pad->Point1.Y, X, Y, cosa, sina);
    free_rotate (&pad->Point2.X, &pad->Point2.Y, X, Y, cosa, sina);
    SetLineBoundingBox ((LineType *) pad);
  }
  END_LOOP;
  ARC_LOOP (Element);
  {
    free_rotate (&arc->X, &arc->Y, X, Y, cosa, sina);
    arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
  }
  END_LOOP;

  free_rotate (&Element->MarkX, &Element->MarkY, X, Y, cosa, sina);
  SetElementBoundingBox (Data, Element, &PCB->Font);
  ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
}
Ejemplo n.º 6
0
/* ---------------------------------------------------------------------------
 * moves a element to buffer without allocating memory for pins/names
 */
static void *
MoveElementToBuffer (ElementType *element)
{
  /*
   * Delete the element from the source (remove it from trees,
   * restore to polygons)
   */
  r_delete_element (Source, element);

  Source->Element = g_list_remove (Source->Element, element);
  Source->ElementN --;
  Dest->Element = g_list_append (Dest->Element, element);
  Dest->ElementN ++;

  PIN_LOOP (element);
  {
    RestoreToPolygon(Source, PIN_TYPE, element, pin);
    CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, pin);
  }
  END_LOOP;
  PAD_LOOP (element);
  {
    RestoreToPolygon(Source, PAD_TYPE, element, pad);
    CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, pad);
  }
  END_LOOP;
  SetElementBoundingBox (Dest, element, &PCB->Font);
  /*
   * Now clear the from the polygons in the destination
   */
  PIN_LOOP (element);
  {
    ClearFromPolygon (Dest, PIN_TYPE, element, pin);
  }
  END_LOOP;
  PAD_LOOP (element);
  {
    ClearFromPolygon (Dest, PAD_TYPE, element, pad);
  }
  END_LOOP;

  return element;
}
Ejemplo n.º 7
0
/* ---------------------------------------------------------------------------
 * mirrors the coordinates of an element
 * an additional offset is passed
 */
void
MirrorElementCoordinates (DataTypePtr Data, ElementTypePtr Element,
			  Coord yoff)
{
  r_delete_element (Data, Element);
  ELEMENTLINE_LOOP (Element);
  {
    line->Point1.X = SWAP_X (line->Point1.X);
    line->Point1.Y = SWAP_Y (line->Point1.Y) + yoff;
    line->Point2.X = SWAP_X (line->Point2.X);
    line->Point2.Y = SWAP_Y (line->Point2.Y) + yoff;
  }
  END_LOOP;
  PIN_LOOP (Element);
  {
    RestoreToPolygon (Data, PIN_TYPE, Element, pin);
    pin->X = SWAP_X (pin->X);
    pin->Y = SWAP_Y (pin->Y) + yoff;
  }
  END_LOOP;
  PAD_LOOP (Element);
  {
    RestoreToPolygon (Data, PAD_TYPE, Element, pad);
    pad->Point1.X = SWAP_X (pad->Point1.X);
    pad->Point1.Y = SWAP_Y (pad->Point1.Y) + yoff;
    pad->Point2.X = SWAP_X (pad->Point2.X);
    pad->Point2.Y = SWAP_Y (pad->Point2.Y) + yoff;
    TOGGLE_FLAG (ONSOLDERFLAG, pad);
  }
  END_LOOP;
  ARC_LOOP (Element);
  {
    arc->X = SWAP_X (arc->X);
    arc->Y = SWAP_Y (arc->Y) + yoff;
    arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
    arc->Delta = SWAP_DELTA (arc->Delta);
  }
  END_LOOP;
  ELEMENTTEXT_LOOP (Element);
  {
    text->X = SWAP_X (text->X);
    text->Y = SWAP_Y (text->Y) + yoff;
    TOGGLE_FLAG (ONSOLDERFLAG, text);
  }
  END_LOOP;
  Element->MarkX = SWAP_X (Element->MarkX);
  Element->MarkY = SWAP_Y (Element->MarkY) + yoff;

  /* now toggle the solder-side flag */
  TOGGLE_FLAG (ONSOLDERFLAG, Element);
  /* this inserts all of the rtree data too */
  SetElementBoundingBox (Data, Element, &PCB->Font);
  ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
}
Ejemplo n.º 8
0
PinType *
find_pin (ElementType *element, const char* number)
{
  PIN_LOOP(element);
  {
    if (pin->Number && number_cmp(pin->Number, number) == 0) {
      return pin;
    }
  }
  END_LOOP;
  return NULL;
}
Ejemplo n.º 9
0
/* ---------------------------------------------------------------------------
 * erases all pins and pads of an element
 */
void
EraseElementPinsAndPads (ElementType *Element)
{
  PIN_LOOP (Element);
  {
    ErasePin (pin);
  }
  END_LOOP;
  PAD_LOOP (Element);
  {
    ErasePad (pad);
  }
  END_LOOP;
}
Ejemplo n.º 10
0
/* ---------------------------------------------------------------------------
 * get next slot for an element, allocates memory if necessary
 */
ElementTypePtr
GetElementMemory (DataTypePtr Data)
{
  ElementTypePtr element = Data->Element;
  int i;

  /* realloc new memory if necessary and clear it */
  if (Data->ElementN >= Data->ElementMax)
    {
      Data->ElementMax += STEP_ELEMENT;
      if (Data->element_tree)
	r_destroy_tree (&Data->element_tree);
      element = MyRealloc (element, Data->ElementMax * sizeof (ElementType),
			   "GetElementMemory()");
      Data->Element = element;
      memset (element + Data->ElementN, 0,
	      STEP_ELEMENT * sizeof (ElementType));
      Data->element_tree = r_create_tree (NULL, 0, 0);
      for (i = 0; i < MAX_ELEMENTNAMES; i++)
	{
	  if (Data->name_tree[i])
	    r_destroy_tree (&Data->name_tree[i]);
	  Data->name_tree[i] = r_create_tree (NULL, 0, 0);
	}

      ELEMENT_LOOP (Data);
      {
	r_insert_entry (Data->element_tree, (BoxType *) element, 0);
	PIN_LOOP (element);
	{
	  pin->Element = element;
	}
	END_LOOP;
	PAD_LOOP (element);
	{
	  pad->Element = element;
	}
	END_LOOP;
	ELEMENTTEXT_LOOP (element);
	{
	  text->Element = element;
	  r_insert_entry (Data->name_tree[n], (BoxType *) text, 0);
	}
	END_LOOP;
      }
      END_LOOP;
    }
  return (element + Data->ElementN++);
}
Ejemplo n.º 11
0
/* ---------------------------------------------------------------------------
 * draw pins of an element
 */
void
DrawElementPinsAndPads (ElementType *Element)
{
  PAD_LOOP (Element);
  {
    if (doing_pinout || doing_assy || FRONT (pad) || PCB->InvisibleObjectsOn)
      DrawPad (pad);
  }
  END_LOOP;
  PIN_LOOP (Element);
  {
    DrawPin (pin);
  }
  END_LOOP;
}
Ejemplo n.º 12
0
void
ResetVisitPinsViasAndPads ()
{
  VIA_LOOP (PCB->Data);
    CLEAR_FLAG (VISITFLAG, via);
  END_LOOP; /* Via. */
  ELEMENT_LOOP (PCB->Data);
    PIN_LOOP (element);
      CLEAR_FLAG (VISITFLAG, pin);
    END_LOOP; /* Pin. */
    PAD_LOOP (element);
      CLEAR_FLAG (VISITFLAG, pad);
    END_LOOP; /* Pad. */
  END_LOOP; /* Element. */
}
Ejemplo n.º 13
0
static void
draw_element_pins_and_pads (ElementType *element)
{
  PAD_LOOP (element);
  {
    if (doing_pinout || doing_assy || FRONT (pad) || PCB->InvisibleObjectsOn)
      draw_pad (pad);
  }
  END_LOOP;
  PIN_LOOP (element);
  {
    draw_pin (pin, true);
  }
  END_LOOP;
}
Ejemplo n.º 14
0
static void
netnode_browse (Widget w, XtPointer v, XmListCallbackStruct * cbs)
{
  LibraryMenuType *menu = PCB->NetlistLib.Menu + last_pick;
  char *name = menu->Entry[cbs->item_position - 1].ListEntry;
  char *ename, *pname;

  ename = strdup (name);
  pname = strchr (ename, '-');
  if (! pname)
    {
      free (ename);
      return;
    }
  *pname++ = 0;

  ELEMENT_LOOP (PCB->Data);
  {
    char *es = element->Name[NAMEONPCB_INDEX].TextString;
    if (es && strcmp (es, ename) == 0)
      {
	PIN_LOOP (element);
	{
	  if (strcmp (pin->Number, pname) == 0)
	    {
	      MoveCrosshairAbsolute (pin->X, pin->Y);
	      free (ename);
	      return;
	    }
	}
	END_LOOP;
	PAD_LOOP (element);
	{
	  if (strcmp (pad->Number, pname) == 0)
	    {
	      int x = (pad->Point1.X + pad->Point2.X) / 2;
	      int y = (pad->Point1.Y + pad->Point2.Y) / 2;
	      gui->set_crosshair (x, y, HID_SC_PAN_VIEWPORT);
	      free (ename);
	      return;
	    }
	}
	END_LOOP;
      }
  }
  END_LOOP;
  free (ename);
}
Ejemplo n.º 15
0
Archivo: report.c Proyecto: thequux/pcb
static int
ReportFoundPins (int argc, char **argv, int x, int y)
{
  static DynamicStringType list;
  char temp[64];
  int col = 0;

  DSClearString (&list);
  DSAddString (&list, "The following pins/pads are FOUND:\n");
  ELEMENT_LOOP (PCB->Data);
  {
    PIN_LOOP (element);
    {
      if (TEST_FLAG (FOUNDFLAG, pin))
	{
	  sprintf (temp, "%s-%s,%c",
		   NAMEONPCB_NAME (element),
		   pin->Number,
		   ((col++ % (COLUMNS + 1)) == COLUMNS) ? '\n' : ' ');
	  DSAddString (&list, temp);
	}
    }
    END_LOOP;
    PAD_LOOP (element);
    {
      if (TEST_FLAG (FOUNDFLAG, pad))
	{
	  sprintf (temp, "%s-%s,%c",
		   NAMEONPCB_NAME (element), pad->Number,
		   ((col++ % (COLUMNS + 1)) == COLUMNS) ? '\n' : ' ');
	  DSAddString (&list, temp);
	}
    }
    END_LOOP;
  }
  END_LOOP;

  HideCrosshair (false);
  gui->report_dialog ("Report", list.Data);
  RestoreCrosshair (false);
  return 0;
}
Ejemplo n.º 16
0
void
LookupRatLines (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
{
  switch (Type)
    {
    case ELEMENT_TYPE:
      {
	ElementType *element = (ElementType *) Ptr1;

	PIN_LOOP (element);
	{
	  CheckPinForRat (pin);
	}
	END_LOOP;
	PAD_LOOP (element);
	{
	  CheckPadForRat (pad);
	}
	END_LOOP;
	break;
      }

    case LINE_TYPE:
      {
	LayerType *layer = (LayerType *) Ptr1;
	LineType *line = (LineType *) Ptr2;

	CheckLinePointForRat (layer, &line->Point1);
	CheckLinePointForRat (layer, &line->Point2);
	break;
      }

    case LINEPOINT_TYPE:
      CheckLinePointForRat ((LayerType *) Ptr1, (PointType *) Ptr3);
      break;

    case VIA_TYPE:
      CheckPinForRat ((PinType *) Ptr1);
      break;
    }
}
Ejemplo n.º 17
0
/* ---------------------------------------------------------------------------
 * destroys a element
 */
static void *
DestroyElement (ElementTypePtr Element)
{
  if (DestroyTarget->element_tree)
    r_delete_entry (DestroyTarget->element_tree, (BoxType *) Element);
  if (DestroyTarget->pin_tree)
    {
      PIN_LOOP (Element);
      {
	r_delete_entry (DestroyTarget->pin_tree, (BoxType *) pin);
      }
      END_LOOP;
    }
  if (DestroyTarget->pad_tree)
    {
      PAD_LOOP (Element);
      {
	r_delete_entry (DestroyTarget->pad_tree, (BoxType *) pad);
      }
      END_LOOP;
    }
  ELEMENTTEXT_LOOP (Element);
  {
    if (DestroyTarget->name_tree[n])
      r_delete_entry (DestroyTarget->name_tree[n], (BoxType *) text);
  }
  END_LOOP;
  FreeElementMemory (Element);

  DestroyTarget->Element = g_list_remove (DestroyTarget->Element, Element);
  DestroyTarget->ElementN --;

  g_slice_free (ElementType, Element);

  return NULL;
}
Ejemplo n.º 18
0
Archivo: report.c Proyecto: veox/pcb
static int
ReportNetLength (int argc, char **argv, Coord x, Coord y)
{
  Coord length = 0;
  char *netname = 0;
  int found = 0;

  gui->get_coords (_("Click on a connection"), &x, &y);

  /* Reset all connection flags and save an undo-state to get back
   * to the state the board was in when we started this function.
   *
   * After this, we don't add any changes to the undo system, but
   * ensure we get back to a point where we can Undo() our changes
   * by resetting the connections with ClearFlagOnAllObjects() before
   * calling Undo() at the end of the procedure.
   */
  ClearFlagOnAllObjects (true, FOUNDFLAG);
  IncrementUndoSerialNumber ();

  length = XYtoNetLength (x, y, &found);

  if (!found)
    {
      ClearFlagOnAllObjects (false, FOUNDFLAG);
      Undo (true);
      gui->log (_("No net under cursor.\n"));
      return 1;
    }

  ELEMENT_LOOP (PCB->Data);
  {
    PIN_LOOP (element);
    {
      if (TEST_FLAG (FOUNDFLAG, pin))
	{
	  int ni, nei;
	  char *ename = element->Name[NAMEONPCB_INDEX].TextString;
	  char *pname = pin->Number;
	  char *n;

	  if (ename && pname)
	    {
	      n = Concat (ename, _("-"), pname, NULL);
	      for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++)
		for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++)
		  {
		    if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0)
		      {
			netname = PCB->NetlistLib.Menu[ni].Name + 2;
			goto got_net_name; /* four for loops deep */
		      }
		  }
	    }
	}
    }
    END_LOOP;
    PAD_LOOP (element);
    {
      if (TEST_FLAG (FOUNDFLAG, pad))
	{
	  int ni, nei;
	  char *ename = element->Name[NAMEONPCB_INDEX].TextString;
	  char *pname = pad->Number;
	  char *n;

	  if (ename && pname)
	    {
	      n = Concat (ename, _("-"), pname, NULL);
	      for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++)
		for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++)
		  {
		    if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0)
		      {
			netname = PCB->NetlistLib.Menu[ni].Name + 2;
			goto got_net_name; /* four for loops deep */
		      }
		  }
	    }
	}
    }
    END_LOOP;
  }
  END_LOOP;

got_net_name:
  ClearFlagOnAllObjects (false, FOUNDFLAG);
  Undo (true);

  {
    char buf[50];
    pcb_snprintf(buf, sizeof (buf), _("%$m*"), Settings.grid_unit->suffix, length);
    if (netname)
      gui->log (_("Net \"%s\" length: %s\n"), netname, buf);
    else
      gui->log (_("Net length: %s\n"), buf);
  }

  return 0;
}
Ejemplo n.º 19
0
Archivo: report.c Proyecto: veox/pcb
static int
ReportAllNetLengths (int argc, char **argv, Coord x, Coord y)
{
  int ni;
  int found;

  /* Reset all connection flags and save an undo-state to get back
   * to the state the board was in when we started this function.
   *
   * After this, we don't add any changes to the undo system, but
   * ensure we get back to a point where we can Undo() our changes
   * by resetting the connections with ClearFlagOnAllObjects() before
   * calling Undo() at the end of the procedure.
   */
  ClearFlagOnAllObjects (true, FOUNDFLAG);
  IncrementUndoSerialNumber ();

  for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++)
    {
      char *netname = PCB->NetlistLib.Menu[ni].Name + 2;
      char *ename = PCB->NetlistLib.Menu[ni].Entry[0].ListEntry;
      char *pname;
      bool got_one = 0;

      ename = strdup (ename);
      pname = strchr (ename, '-');
      if (! pname)
	{
	  free (ename);
	  continue;
	}
      *pname++ = 0;

      ELEMENT_LOOP (PCB->Data);
      {
	char *es = element->Name[NAMEONPCB_INDEX].TextString;
	if (es && strcmp (es, ename) == 0)
	  {
	    PIN_LOOP (element);
	    {
	      if (strcmp (pin->Number, pname) == 0)
		{
		  x = pin->X;
		  y = pin->Y;
		  got_one = 1;
                  break;
		}
	    }
	    END_LOOP;
	    PAD_LOOP (element);
	    {
	      if (strcmp (pad->Number, pname) == 0)
		{
		  x = (pad->Point1.X + pad->Point2.X) / 2;
		  y = (pad->Point1.Y + pad->Point2.Y) / 2;
		  got_one = 1;
                  break;
		}
	    }
	    END_LOOP;
	  }
      }
      END_LOOP;

      if (got_one)
        {
          char buf[50];
          const char *units_name = argv[0];
          Coord length;

          if (argc < 1)
            units_name = Settings.grid_unit->suffix;

          length = XYtoNetLength (x, y, &found);

          /* Reset connectors for the next lookup */
          ClearFlagOnAllObjects (false, FOUNDFLAG);

          pcb_snprintf(buf, sizeof (buf), _("%$m*"), units_name, length);
          gui->log(_("Net %s length %s\n"), netname, buf);
        }
    }

  ClearFlagOnAllObjects (false, FOUNDFLAG);
  Undo (true);
  return 0;
}
Ejemplo n.º 20
0
Archivo: report.c Proyecto: veox/pcb
static int
ReportDialog (int argc, char **argv, Coord x, Coord y)
{
  void *ptr1, *ptr2, *ptr3;
  int type;
  char report[2048];

  type = SearchScreen (x, y, REPORT_TYPES, &ptr1, &ptr2, &ptr3);
  if (type == NO_TYPE)
    type =
      SearchScreen (x, y, REPORT_TYPES | LOCKED_TYPE, &ptr1, &ptr2, &ptr3);

  switch (type)
    {
    case VIA_TYPE:
      {
	PinType *via;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    __r_dump_tree (PCB->Data->via_tree->root, 0);
	    return 0;
	  }
#endif
	via = (PinType *) ptr2;
	if (TEST_FLAG (HOLEFLAG, via))
	  pcb_snprintf (report, sizeof (report), _("%m+VIA ID# %ld; Flags:%s\n"
		   "(X,Y) = %$mD.\n"
		   "It is a pure hole of diameter %$mS.\n"
		   "Name = \"%s\"."
		   "%s"), USER_UNITMASK, via->ID, flags_to_string (via->Flags, VIA_TYPE),
		   via->X, via->Y, via->DrillingHole, EMPTY (via->Name),
		   TEST_FLAG (LOCKFLAG, via) ? _("It is LOCKED.\n") : "");
	else
	  pcb_snprintf (report, sizeof (report), _("%m+VIA ID# %ld;  Flags:%s\n"
		   "(X,Y) = %$mD.\n"
		   "Copper width = %$mS. Drill width = %$mS.\n"
		   "Clearance width in polygons = %$mS.\n"
		   "Annulus = %$mS.\n"
		   "Solder mask hole = %$mS (gap = %$mS).\n"
		   "Name = \"%s\"."
		   "%s"), USER_UNITMASK, via->ID, flags_to_string (via->Flags, VIA_TYPE),
		   via->X, via->Y,
		   via->Thickness,
		   via->DrillingHole,
		   via->Clearance / 2,
		   (via->Thickness - via->DrillingHole) / 2,
		   via->Mask,
		   (via->Mask - via->Thickness) / 2,
		   EMPTY (via->Name), TEST_FLAG (LOCKFLAG, via) ?
		   _("It is LOCKED.\n") : "");
	break;
      }
    case PIN_TYPE:
      {
	PinType *Pin;
	ElementType *element;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    __r_dump_tree (PCB->Data->pin_tree->root, 0);
	    return 0;
	  }
#endif
	Pin = (PinType *) ptr2;
	element = (ElementType *) ptr1;

	PIN_LOOP (element);
	{
	  if (pin == Pin)
	    break;
	}
	END_LOOP;
	if (TEST_FLAG (HOLEFLAG, Pin))
	  pcb_snprintf (report, sizeof (report), _("%m+PIN ID# %ld; Flags:%s\n"
		   "(X,Y) = %$mD.\n"
		   "It is a mounting hole. Drill width = %$mS.\n"
		   "It is owned by element %$mS.\n"
		   "%s"), USER_UNITMASK, Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE),
		   Pin->X, Pin->Y, Pin->DrillingHole,
		   EMPTY (element->Name[1].TextString),
		   TEST_FLAG (LOCKFLAG, Pin) ? _("It is LOCKED.\n") : "");
	else
	  pcb_snprintf (report, sizeof (report),
		   _("%m+PIN ID# %ld;  Flags:%s\n" "(X,Y) = %$mD.\n"
		   "Copper width = %$mS. Drill width = %$mS.\n"
		   "Clearance width to Polygon = %$mS.\n"
		   "Annulus = %$mS.\n"
		   "Solder mask hole = %$mS (gap = %$mS).\n"
		   "Name = \"%s\".\n"
		   "It is owned by element %s\n as pin number %s.\n"
		   "%s"), USER_UNITMASK,
		   Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE),
		   Pin->X, Pin->Y, Pin->Thickness,
		   Pin->DrillingHole,
		   Pin->Clearance / 2,
		   (Pin->Thickness - Pin->DrillingHole) / 2,
		   Pin->Mask,
		   (Pin->Mask - Pin->Thickness) / 2,
		   EMPTY (Pin->Name),
		   EMPTY (element->Name[1].TextString), EMPTY (Pin->Number),
		   TEST_FLAG (LOCKFLAG, Pin) ? _("It is LOCKED.\n") : "");
	break;
      }
    case LINE_TYPE:
      {
	LineType *line;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    LayerType *layer = (LayerType *) ptr1;
	    __r_dump_tree (layer->line_tree->root, 0);
	    return 0;
	  }
#endif
	line = (LineType *) ptr2;
	pcb_snprintf (report, sizeof (report), _("%m+LINE ID# %ld;  Flags:%s\n"
		 "FirstPoint(X,Y)  = %$mD, ID = %ld.\n"
		 "SecondPoint(X,Y) = %$mD, ID = %ld.\n"
		 "Width = %$mS.\nClearance width in polygons = %$mS.\n"
		 "It is on layer %d\n"
		 "and has name \"%s\".\n"
		 "%s"), USER_UNITMASK,
		 line->ID, flags_to_string (line->Flags, LINE_TYPE),
		 line->Point1.X, line->Point1.Y, line->Point1.ID,
		 line->Point2.X, line->Point2.Y, line->Point2.ID,
		 line->Thickness, line->Clearance / 2,
		 GetLayerNumber (PCB->Data, (LayerType *) ptr1),
		 UNKNOWN (line->Number),
		 TEST_FLAG (LOCKFLAG, line) ? _("It is LOCKED.\n") : "");
	break;
      }
    case RATLINE_TYPE:
      {
	RatType *line;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    __r_dump_tree (PCB->Data->rat_tree->root, 0);
	    return 0;
	  }
#endif
	line = (RatType *) ptr2;
	pcb_snprintf (report, sizeof (report), _("%m+RAT-LINE ID# %ld;  Flags:%s\n"
		 "FirstPoint(X,Y)  = %$mD; ID = %ld; "
		 "connects to layer group %d.\n"
		 "SecondPoint(X,Y) = %$mD; ID = %ld; "
		 "connects to layer group %d.\n"),
		 USER_UNITMASK, line->ID, flags_to_string (line->Flags, LINE_TYPE),
		 line->Point1.X, line->Point1.Y,
		 line->Point1.ID, line->group1,
		 line->Point2.X, line->Point2.Y,
		 line->Point2.ID, line->group2);
	break;
      }
    case ARC_TYPE:
      {
	ArcType *Arc;
	BoxType *box;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    LayerType *layer = (LayerType *) ptr1;
	    __r_dump_tree (layer->arc_tree->root, 0);
	    return 0;
	  }
#endif
	Arc = (ArcType *) ptr2;
	box = GetArcEnds (Arc);

	pcb_snprintf (report, sizeof (report), _("%m+ARC ID# %ld;  Flags:%s\n"
		 "CenterPoint(X,Y) = %$mD.\n"
		 "Radius = %$mS, Thickness = %$mS.\n"
		 "Clearance width in polygons = %$mS.\n"
		 "StartAngle = %ma degrees, DeltaAngle = %ma degrees.\n"
		 "Bounding Box is %$mD, %$mD.\n"
		 "That makes the end points at %$mD and %$mD.\n"
		 "It is on layer %d.\n"
		 "%s"), USER_UNITMASK, Arc->ID, flags_to_string (Arc->Flags, ARC_TYPE),
		 Arc->X, Arc->Y,
		 Arc->Width, Arc->Thickness,
		 Arc->Clearance / 2, Arc->StartAngle, Arc->Delta,
		 Arc->BoundingBox.X1, Arc->BoundingBox.Y1,
		 Arc->BoundingBox.X2, Arc->BoundingBox.Y2,
		 box->X1, box->Y1,
		 box->X2, box->Y2,
		 GetLayerNumber (PCB->Data, (LayerType *) ptr1),
		 TEST_FLAG (LOCKFLAG, Arc) ? _("It is LOCKED.\n") : "");
	break;
      }
    case POLYGON_TYPE:
      {
	PolygonType *Polygon;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    LayerType *layer = (LayerType *) ptr1;
	    __r_dump_tree (layer->polygon_tree->root, 0);
	    return 0;
	  }
#endif
	Polygon = (PolygonType *) ptr2;

	pcb_snprintf (report, sizeof (report), _("%m+POLYGON ID# %ld;  Flags:%s\n"
		 "Its bounding box is %$mD %$mD.\n"
		 "It has %d points and could store %d more\n"
		 "  without using more memory.\n"
		 "It has %d holes and resides on layer %d.\n"
		 "%s"), USER_UNITMASK, Polygon->ID,
		 flags_to_string (Polygon->Flags, POLYGON_TYPE),
		 Polygon->BoundingBox.X1, Polygon->BoundingBox.Y1,
		 Polygon->BoundingBox.X2, Polygon->BoundingBox.Y2,
		 Polygon->PointN, Polygon->PointMax - Polygon->PointN,
		 Polygon->HoleIndexN,
		 GetLayerNumber (PCB->Data, (LayerType *) ptr1),
		 TEST_FLAG (LOCKFLAG, Polygon) ? _("It is LOCKED.\n") : "");
	break;
      }
    case PAD_TYPE:
      {
	Coord len;
	PadType *Pad;
	ElementType *element;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    __r_dump_tree (PCB->Data->pad_tree->root, 0);
	    return 0;
	  }
#endif
	Pad = (PadType *) ptr2;
	element = (ElementType *) ptr1;

	PAD_LOOP (element);
	{
	  {
	    if (pad == Pad)
	      break;
	  }
	}
	END_LOOP;
	len = Distance (Pad->Point1.X, Pad->Point1.Y, Pad->Point2.X, Pad->Point2.Y);
	pcb_snprintf (report, sizeof (report), _("%m+PAD ID# %ld;  Flags:%s\n"
		 "FirstPoint(X,Y)  = %$mD; ID = %ld.\n"
		 "SecondPoint(X,Y) = %$mD; ID = %ld.\n"
		 "Width = %$mS.  Length = %$mS.\n"
		 "Clearance width in polygons = %$mS.\n"
		 "Solder mask = %$mS x %$mS (gap = %$mS).\n"
		 "Name = \"%s\".\n"
		 "It is owned by SMD element %s\n"
		 "  as pin number %s and is on the %s\n"
		 "side of the board.\n"
		 "%s"), USER_UNITMASK, Pad->ID,
		 flags_to_string (Pad->Flags, PAD_TYPE),
		 Pad->Point1.X, Pad->Point1.Y, Pad->Point1.ID,
		 Pad->Point2.X, Pad->Point2.Y, Pad->Point2.ID,
		 Pad->Thickness, len + Pad->Thickness,
		 Pad->Clearance / 2,
		 Pad->Mask, len + Pad->Mask,
		 (Pad->Mask - Pad->Thickness) / 2,
		 EMPTY (Pad->Name),
		 EMPTY (element->Name[1].TextString),
		 EMPTY (Pad->Number),
		 TEST_FLAG (ONSOLDERFLAG,
			    Pad) ? _("solder (bottom)") : _("component"),
		 TEST_FLAG (LOCKFLAG, Pad) ? _("It is LOCKED.\n") : "");
	break;
      }
    case ELEMENT_TYPE:
      {
	ElementType *element;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    __r_dump_tree (PCB->Data->element_tree->root, 0);
	    return 0;
	  }
#endif
	element = (ElementType *) ptr2;
	pcb_snprintf (report, sizeof (report), _("%m+ELEMENT ID# %ld;  Flags:%s\n"
		 "BoundingBox %$mD %$mD.\n"
		 "Descriptive Name \"%s\".\n"
		 "Name on board \"%s\".\n"
		 "Part number name \"%s\".\n"
		 "It is %$mS tall and is located at (X,Y) = %$mD %s.\n"
		 "Mark located at point (X,Y) = %$mD.\n"
		 "It is on the %s side of the board.\n"
		 "%s"), USER_UNITMASK,
		 element->ID, flags_to_string (element->Flags, ELEMENT_TYPE),
		 element->BoundingBox.X1, element->BoundingBox.Y1,
		 element->BoundingBox.X2, element->BoundingBox.Y2,
		 EMPTY (element->Name[0].TextString),
		 EMPTY (element->Name[1].TextString),
		 EMPTY (element->Name[2].TextString),
		 SCALE_TEXT (FONT_CAPHEIGHT, element->Name[1].Scale),
		 element->Name[1].X, element->Name[1].Y,
		 TEST_FLAG (HIDENAMEFLAG, element) ? _(",\n  but it's hidden") : "",
		 element->MarkX, element->MarkY,
		 TEST_FLAG (ONSOLDERFLAG, element) ? _("solder (bottom)") : _("component"),
		 TEST_FLAG (LOCKFLAG, element) ? _("It is LOCKED.\n") : "");
	break;
      }
    case TEXT_TYPE:
#ifndef NDEBUG
      if (gui->shift_is_pressed ())
	{
	  LayerType *layer = (LayerType *) ptr1;
	  __r_dump_tree (layer->text_tree->root, 0);
	  return 0;
	}
#endif
    case ELEMENTNAME_TYPE:
      {
	char laynum[32];
	TextType *text;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    __r_dump_tree (PCB->Data->name_tree[NAME_INDEX (PCB)]->root, 0);
	    return 0;
	  }
#endif
	text = (TextType *) ptr2;

	if (type == TEXT_TYPE)
	  sprintf (laynum, _("It is on layer %d."),
		   GetLayerNumber (PCB->Data, (LayerType *) ptr1));
	pcb_snprintf (report, sizeof (report), _("%m+TEXT ID# %ld;  Flags:%s\n"
		 "Located at (X,Y) = %$mD.\n"
		 "Characters are %$mS tall.\n"
		 "Value is \"%s\".\n"
		 "Direction is %d.\n"
		 "The bounding box is %$mD %$mD.\n"
		 "%s\n"
		 "%s"), USER_UNITMASK, text->ID, flags_to_string (text->Flags, TEXT_TYPE),
		 text->X, text->Y, SCALE_TEXT (FONT_CAPHEIGHT, text->Scale),
		 text->TextString, text->Direction,
		 text->BoundingBox.X1, text->BoundingBox.Y1,
		 text->BoundingBox.X2, text->BoundingBox.Y2,
		 (type == TEXT_TYPE) ? laynum : _("It is an element name."),
		 TEST_FLAG (LOCKFLAG, text) ? _("It is LOCKED.\n") : "");
	break;
      }
    case LINEPOINT_TYPE:
    case POLYGONPOINT_TYPE:
      {
	PointType *point = (PointType *) ptr2;
	pcb_snprintf (report, sizeof (report), _("%m+POINT ID# %ld.\n"
		 "Located at (X,Y) = %$mD.\n"
		 "It belongs to a %s on layer %d.\n"), USER_UNITMASK, point->ID,
		 point->X, point->Y,
		 (type == LINEPOINT_TYPE) ?
		     C_("report", "line") : C_("report", "polygon"),
		 GetLayerNumber (PCB->Data, (LayerType *) ptr1));
	break;
      }
    case NO_TYPE:
      report[0] = '\0';
      break;

    default:
      sprintf (report, _("Unknown\n"));
      break;
    }

  if (report[0] == '\0')
    {
      Message (_("Nothing found to report on\n"));
      return 1;
    }
  /* create dialog box */
  gui->report_dialog (_("Report"), report);

  return 0;
}
Ejemplo n.º 21
0
/* ---------------------------------------------------------------------------
 * draws the elements of a loaded circuit which is to be merged in
 */
static void
XORDrawElement (ElementTypePtr Element, LocationType DX, LocationType DY)
{
  /* if no silkscreen, draw the bounding box */
  if (Element->ArcN == 0 && Element->LineN == 0)
    {
      gui->draw_line (Crosshair.GC,
		      DX + Element->BoundingBox.X1,
		      DY + Element->BoundingBox.Y1,
		      DX + Element->BoundingBox.X1,
		      DY + Element->BoundingBox.Y2);
      gui->draw_line (Crosshair.GC,
		      DX + Element->BoundingBox.X1,
		      DY + Element->BoundingBox.Y2,
		      DX + Element->BoundingBox.X2,
		      DY + Element->BoundingBox.Y2);
      gui->draw_line (Crosshair.GC,
		      DX + Element->BoundingBox.X2,
		      DY + Element->BoundingBox.Y2,
		      DX + Element->BoundingBox.X2,
		      DY + Element->BoundingBox.Y1);
      gui->draw_line (Crosshair.GC,
		      DX + Element->BoundingBox.X2,
		      DY + Element->BoundingBox.Y1,
		      DX + Element->BoundingBox.X1,
		      DY + Element->BoundingBox.Y1);
    }
  else
    {
      ELEMENTLINE_LOOP (Element);
      {
	gui->draw_line (Crosshair.GC,
			DX + line->Point1.X,
			DY + line->Point1.Y,
			DX + line->Point2.X, DY + line->Point2.Y);
      }
      END_LOOP;

      /* arc coordinates and angles have to be converted to X11 notation */
      ARC_LOOP (Element);
      {
	gui->draw_arc (Crosshair.GC,
		       DX + arc->X,
		       DY + arc->Y,
		       arc->Width, arc->Height, arc->StartAngle, arc->Delta);
      }
      END_LOOP;
    }
  /* pin coordinates and angles have to be converted to X11 notation */
  PIN_LOOP (Element);
  {
    gui->draw_arc (Crosshair.GC,
		   DX + pin->X,
		   DY + pin->Y,
		   pin->Thickness / 2, pin->Thickness / 2, 0, 360);
  }
  END_LOOP;

  /* pads */
  PAD_LOOP (Element);
  {
    if ((TEST_FLAG (ONSOLDERFLAG, pad) != 0) ==
	Settings.ShowSolderSide || PCB->InvisibleObjectsOn)
      {
	if (pad->Point1.X == pad->Point2.X
	    || pad->Point1.Y == pad->Point2.Y)
	  {
	    int minx, miny, maxx, maxy;
	    minx = DX + MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness/2;
	    maxx = DX + MAX (pad->Point1.X, pad->Point2.X) + pad->Thickness/2;
	    miny = DY + MIN (pad->Point1.Y, pad->Point2.Y) - pad->Thickness/2;
	    maxy = DY + MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness/2;
	    gui->draw_line (Crosshair.GC, minx, miny, maxx, miny);
	    gui->draw_line (Crosshair.GC, minx, miny, minx, maxy);
	    gui->draw_line (Crosshair.GC, maxx, miny, maxx, maxy);
	    gui->draw_line (Crosshair.GC, minx, maxy, maxx, maxy);
	  }
	else
	  {
	    /* FIXME: draw outlines, not centerlines.  */
	    gui->draw_line (Crosshair.GC,
			    DX + pad->Point1.X, DY + pad->Point1.Y,
			    DX + pad->Point2.X, DY + pad->Point2.Y);
	  }
      }
  }
  END_LOOP;
  /* mark */
  gui->draw_line (Crosshair.GC,
		  Element->MarkX + DX - EMARK_SIZE,
		  Element->MarkY + DY,
		  Element->MarkX + DX, Element->MarkY + DY - EMARK_SIZE);
  gui->draw_line (Crosshair.GC,
		  Element->MarkX + DX + EMARK_SIZE,
		  Element->MarkY + DY,
		  Element->MarkX + DX, Element->MarkY + DY - EMARK_SIZE);
  gui->draw_line (Crosshair.GC,
		  Element->MarkX + DX - EMARK_SIZE,
		  Element->MarkY + DY,
		  Element->MarkX + DX, Element->MarkY + DY + EMARK_SIZE);
  gui->draw_line (Crosshair.GC,
		  Element->MarkX + DX + EMARK_SIZE,
		  Element->MarkY + DY,
		  Element->MarkX + DX, Element->MarkY + DY + EMARK_SIZE);
}
Ejemplo n.º 22
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);
}
Ejemplo n.º 23
0
Archivo: report.c Proyecto: thequux/pcb
static int
ReportNetLength (int argc, char **argv, int x, int y)
{
  double length = 0;
  char *netname = 0;
  int found = 0;

  if (ResetConnections (true))
    Draw ();
  /* NB: XYtoNetLength calls LookupConnection, which performs an undo
   *     serial number update, so we don't need to add one here.
   */
  gui->get_coords ("Click on a connection", &x, &y);

  length = XYtoNetLength (x, y, &found);

  if (!found)
    {
      gui->log ("No net under cursor.\n");
      return 1;
    }

  ELEMENT_LOOP (PCB->Data);
  {
    PIN_LOOP (element);
    {
      if (TEST_FLAG (FOUNDFLAG, pin))
	{
	  int ni, nei;
	  char *ename = element->Name[NAMEONPCB_INDEX].TextString;
	  char *pname = pin->Number;
	  char *n;

	  if (ename && pname)
	    {
	      n = Concat (ename, "-", pname, NULL);
	      for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++)
		for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++)
		  {
		    if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0)
		      {
			netname = PCB->NetlistLib.Menu[ni].Name + 2;
			goto got_net_name; /* four for loops deep */
		      }
		  }
	    }
	}
    }
    END_LOOP;
    PAD_LOOP (element);
    {
      if (TEST_FLAG (FOUNDFLAG, pad))
	{
	  int ni, nei;
	  char *ename = element->Name[NAMEONPCB_INDEX].TextString;
	  char *pname = pad->Number;
	  char *n;

	  if (ename && pname)
	    {
	      n = Concat (ename, "-", pname, NULL);
	      for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++)
		for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++)
		  {
		    if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0)
		      {
			netname = PCB->NetlistLib.Menu[ni].Name + 2;
			goto got_net_name; /* four for loops deep */
		      }
		  }
	    }
	}
    }
    END_LOOP;
  }
  END_LOOP;
 got_net_name:

  HideCrosshair (false);
  {
    int prec = Settings.grid_units_mm? 4: 2;
    if (netname)
      gui->log ("Net \"%s\" length: %.*f %s\n", netname, prec, UNIT (length));
    else
      gui->log ("Net length: %.*f %s\n", prec, UNIT (length));
  }
  RestoreCrosshair (false);
  return 0;
}
Ejemplo n.º 24
0
Archivo: report.c Proyecto: thequux/pcb
static int
ReportDialog (int argc, char **argv, int x, int y)
{
  void *ptr1, *ptr2, *ptr3;
  int type, prec = Settings.grid_units_mm? 4: 2;
  char report[2048];

  type = SearchScreen (x, y, REPORT_TYPES, &ptr1, &ptr2, &ptr3);
  if (type == NO_TYPE)
    type =
      SearchScreen (x, y, REPORT_TYPES | LOCKED_TYPE, &ptr1, &ptr2, &ptr3);

  switch (type)
    {
    case VIA_TYPE:
      {
	PinTypePtr via;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    __r_dump_tree (PCB->Data->via_tree->root, 0);
	    return 0;
	  }
#endif
	via = (PinTypePtr) ptr2;
	if (TEST_FLAG (HOLEFLAG, via))
	  sprintf (&report[0], "VIA ID# %ld; Flags:%s\n"
		   "(X,Y) = (%.*f, %.*f) %s.\n"
		   "It is a pure hole of diameter %.*f %s.\n"
		   "Name = \"%s\"."
		   "%s", via->ID, flags_to_string (via->Flags, VIA_TYPE),
		   prec, units (via->X), prec, UNIT (via->Y),
		   prec, UNIT (via->DrillingHole),
		   EMPTY (via->Name), TEST_FLAG (LOCKFLAG,
						 via) ? "It is LOCKED.\n" :
		   "");
	else
	  sprintf (&report[0], "VIA ID# %ld;  Flags:%s\n"
		   "(X,Y) = (%.*f, %.*f) %s.\n"
		   "Copper width = %0.*f %s. Drill width = %0.*f %s.\n"
		   "Clearance width in polygons = %0.*f %s.\n"
		   "Annulus = %0.*f %s.\n"
		   "Solder mask hole = %0.*f %s (gap = %0.*f %s).\n"
		   "Name = \"%s\"."
		   "%s", via->ID, flags_to_string (via->Flags, VIA_TYPE),
		   prec, units (via->X), prec, UNIT (via->Y),
		   prec, UNIT (via->Thickness),
		   prec, UNIT (via->DrillingHole),
		   prec, UNIT (via->Clearance / 2.),
		   prec, UNIT ((via->Thickness - via->DrillingHole)/2),
		   prec, UNIT (via->Mask),
		   prec, UNIT ((via->Mask - via->Thickness)/2),
		   EMPTY (via->Name), TEST_FLAG (LOCKFLAG, via) ?
		   "It is LOCKED.\n" : "");
	break;
      }
    case PIN_TYPE:
      {
	PinTypePtr Pin;
	ElementTypePtr element;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    __r_dump_tree (PCB->Data->pin_tree->root, 0);
	    return 0;
	  }
#endif
	Pin = (PinTypePtr) ptr2;
	element = (ElementTypePtr) ptr1;

	PIN_LOOP (element);
	{
	  if (pin == Pin)
	    break;
	}
	END_LOOP;
	if (TEST_FLAG (HOLEFLAG, Pin))
	  sprintf (&report[0], "PIN ID# %ld; Flags:%s\n"
		   "(X,Y) = (%.*f, %.*f) %s.\n"
		   "It is a mounting hole. Drill width = %0.*f %s.\n"
		   "It is owned by element %s.\n"
		   "%s", Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE),
		   prec, units (Pin->X), prec, UNIT (Pin->Y),
		   prec, UNIT (Pin->DrillingHole),
		   EMPTY (element->Name[1].TextString),
		   TEST_FLAG (LOCKFLAG, Pin) ? "It is LOCKED.\n" : "");
	else
	  sprintf (&report[0],
		   "PIN ID# %ld;  Flags:%s\n" "(X,Y) = (%.*f, %.*f) %s.\n"
		   "Copper width = %0.*f %s. Drill width = %0.*f %s.\n"
		   "Clearance width to Polygon = %0.*f %s.\n"
		   "Annulus = %0.*f %s.\n"
		   "Solder mask hole = %0.*f %s (gap = %0.*f %s).\n"
		   "Name = \"%s\".\n"
		   "It is owned by element %s\n as pin number %s.\n"
		   "%s",
		   Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE),
		   prec, units(Pin->X), prec, UNIT(Pin->Y),
		   prec, UNIT (Pin->Thickness),
		   prec, UNIT (Pin->DrillingHole),
		   prec, UNIT (Pin->Clearance / 2.),
		   prec, UNIT ((Pin->Thickness - Pin->DrillingHole)/2),
		   prec, UNIT (Pin->Mask),
		   prec, UNIT ((Pin->Mask - Pin->Thickness)/2),
		   EMPTY (Pin->Name),
		   EMPTY (element->Name[1].TextString), EMPTY (Pin->Number),
		   TEST_FLAG (LOCKFLAG, Pin) ? "It is LOCKED.\n" : "");
	break;
      }
    case LINE_TYPE:
      {
	LineTypePtr line;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    LayerTypePtr layer = (LayerTypePtr) ptr1;
	    __r_dump_tree (layer->line_tree->root, 0);
	    return 0;
	  }
#endif
	line = (LineTypePtr) ptr2;
	sprintf (&report[0], "LINE ID# %ld;  Flags:%s\n"
		 "FirstPoint(X,Y)  = (%.*f, %.*f) %s, ID = %ld.\n"
		 "SecondPoint(X,Y) = (%.*f, %.*f) %s, ID = %ld.\n"
		 "Width = %0.*f %s.\nClearance width in polygons = %0.*f %s.\n"
		 "It is on layer %d\n"
		 "and has name \"%s\".\n"
		 "%s",
		 line->ID, flags_to_string (line->Flags, LINE_TYPE),
		 prec, units (line->Point1.X), prec, UNIT (line->Point1.Y),
		 line->Point1.ID, prec, units (line->Point2.X), prec, UNIT (line->Point2.Y),
		 line->Point2.ID, prec, UNIT (line->Thickness),
		 prec, UNIT (line->Clearance / 2.), GetLayerNumber (PCB->Data,
							 (LayerTypePtr) ptr1),
		 UNKNOWN (line->Number), TEST_FLAG (LOCKFLAG,
						    line) ? "It is LOCKED.\n" :
		 "");
	break;
      }
    case RATLINE_TYPE:
      {
	RatTypePtr line;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    __r_dump_tree (PCB->Data->rat_tree->root, 0);
	    return 0;
	  }
#endif
	line = (RatTypePtr) ptr2;
	sprintf (&report[0], "RAT-LINE ID# %ld;  Flags:%s\n"
		 "FirstPoint(X,Y)  = (%.*f, %.*f) %s; ID = %ld; "
		 "connects to layer group %d.\n"
		 "SecondPoint(X,Y) = (%.*f, %.*f) %s; ID = %ld; "
		 "connects to layer group %d.\n",
		 line->ID, flags_to_string (line->Flags, LINE_TYPE),
		 prec, units (line->Point1.X), prec, UNIT (line->Point1.Y),
		 line->Point1.ID, line->group1,
		 prec, units (line->Point2.X), prec, UNIT (line->Point2.Y),
		 line->Point2.ID, line->group2);
	break;
      }
    case ARC_TYPE:
      {
	ArcTypePtr Arc;
	BoxTypePtr box;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    LayerTypePtr layer = (LayerTypePtr) ptr1;
	    __r_dump_tree (layer->arc_tree->root, 0);
	    return 0;
	  }
#endif
	Arc = (ArcTypePtr) ptr2;
	box = GetArcEnds (Arc);

	sprintf (&report[0], "ARC ID# %ld;  Flags:%s\n"
		 "CenterPoint(X,Y) = (%.*f, %.*f) %s.\n"
		 "Radius = %0.*f %s, Thickness = %0.*f %s.\n"
		 "Clearance width in polygons = %0.*f %s.\n"
		 "StartAngle = %ld degrees, DeltaAngle = %ld degrees.\n"
		 "Bounding Box is (%.*f,%.*f), (%.*f,%.*f) %s.\n"
		 "That makes the end points at (%.*f,%.*f) %s and (%.*f,%.*f) %s.\n"
		 "It is on layer %d.\n"
		 "%s", Arc->ID, flags_to_string (Arc->Flags, ARC_TYPE),
		 prec, units(Arc->X), prec, UNIT(Arc->Y),
		 prec, UNIT (Arc->Width), prec, UNIT (Arc->Thickness),
		 prec, UNIT (Arc->Clearance / 2.), Arc->StartAngle, Arc->Delta,
		 prec, units (Arc->BoundingBox.X1),
		 prec, units (Arc->BoundingBox.Y1),
		 prec, units (Arc->BoundingBox.X2),
		 prec, UNIT (Arc->BoundingBox.Y2),
		 prec, units (box->X1), prec, UNIT (box->Y1),
		 prec, units (box->X2), prec, UNIT (box->Y2),
		 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1),
		 TEST_FLAG (LOCKFLAG, Arc) ? "It is LOCKED.\n" : "");
	break;
      }
    case POLYGON_TYPE:
      {
	PolygonTypePtr Polygon;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    LayerTypePtr layer = (LayerTypePtr) ptr1;
	    __r_dump_tree (layer->polygon_tree->root, 0);
	    return 0;
	  }
#endif
	Polygon = (PolygonTypePtr) ptr2;

	sprintf (&report[0], "POLYGON ID# %ld;  Flags:%s\n"
		 "Its bounding box is (%.*f,%.*f) (%.*f,%.*f) %s.\n"
		 "It has %d points and could store %d more\n"
		 "  without using more memory.\n"
		 "It has %d holes and resides on layer %d.\n"
		 "%s", Polygon->ID,
		 flags_to_string (Polygon->Flags, POLYGON_TYPE),
		 prec, units(Polygon->BoundingBox.X1),
		 prec, units(Polygon->BoundingBox.Y1),
		 prec, units(Polygon->BoundingBox.X2),
		 prec, UNIT(Polygon->BoundingBox.Y2),
		 Polygon->PointN, Polygon->PointMax - Polygon->PointN,
		 Polygon->HoleIndexN,
		 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1),
		 TEST_FLAG (LOCKFLAG, Polygon) ? "It is LOCKED.\n" : "");
	break;
      }
    case PAD_TYPE:
      {
	int len, dx, dy, mgap;
	PadTypePtr Pad;
	ElementTypePtr element;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    __r_dump_tree (PCB->Data->pad_tree->root, 0);
	    return 0;
	  }
#endif
	Pad = (PadTypePtr) ptr2;
	element = (ElementTypePtr) ptr1;

	PAD_LOOP (element);
	{
	  {
	    if (pad == Pad)
	      break;
	  }
	}
	END_LOOP;
	dx = Pad->Point1.X - Pad->Point2.X;
	dy = Pad->Point1.Y - Pad->Point2.Y;
	len = sqrt (dx*dx+dy*dy);
	mgap = (Pad->Mask - Pad->Thickness)/2;
	sprintf (&report[0], "PAD ID# %ld;  Flags:%s\n"
		 "FirstPoint(X,Y)  = (%.*f, %.*f) %s; ID = %ld.\n"
		 "SecondPoint(X,Y) = (%.*f, %.*f) %s; ID = %ld.\n"
		 "Width = %0.*f %s.  Length = %0.*f %s.\n"
		 "Clearance width in polygons = %0.*f %s.\n"
		 "Solder mask = %0.*f x %0.*f %s (gap = %0.*f %s).\n"
		 "Name = \"%s\".\n"
		 "It is owned by SMD element %s\n"
		 "  as pin number %s and is on the %s\n"
		 "side of the board.\n"
		 "%s", Pad->ID,
		 flags_to_string (Pad->Flags, PAD_TYPE),
		 prec, units (Pad->Point1.X),
		 prec, UNIT (Pad->Point1.Y), Pad->Point1.ID,
		 prec, units (Pad->Point2.X),
		 prec, UNIT (Pad->Point2.Y), Pad->Point2.ID,
		 prec, UNIT (Pad->Thickness),
		 prec, UNIT (len + Pad->Thickness),
		 prec, UNIT (Pad->Clearance / 2.),
		 prec, units (Pad->Mask), prec, UNIT (Pad->Mask + len),
		 prec, UNIT (mgap),
		 EMPTY (Pad->Name),
		 EMPTY (element->Name[1].TextString),
		 EMPTY (Pad->Number),
		 TEST_FLAG (ONSOLDERFLAG,
			    Pad) ? "solder (bottom)" : "component",
		 TEST_FLAG (LOCKFLAG, Pad) ? "It is LOCKED.\n" : "");
	break;
      }
    case ELEMENT_TYPE:
      {
	ElementTypePtr element;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    __r_dump_tree (PCB->Data->element_tree->root, 0);
	    return 0;
	  }
#endif
	element = (ElementTypePtr) ptr2;
	sprintf (&report[0], "ELEMENT ID# %ld;  Flags:%s\n"
		 "BoundingBox (%.*f,%.*f) (%.*f,%.*f) %s.\n"
		 "Descriptive Name \"%s\".\n"
		 "Name on board \"%s\".\n"
		 "Part number name \"%s\".\n"
		 "It is %.*f %s tall and is located at (X,Y) = (%.*f,%.*f)%s.\n"
		 "Mark located at point (X,Y) = (%.*f,%.*f).\n"
		 "It is on the %s side of the board.\n"
		 "%s",
		 element->ID, flags_to_string (element->Flags, ELEMENT_TYPE),
		 prec, units(element->BoundingBox.X1),
		 prec, units (element->BoundingBox.Y1),
		 prec, units(element->BoundingBox.X2),
		 prec, UNIT (element->BoundingBox.Y2),
		 EMPTY (element->Name[0].TextString),
		 EMPTY (element->Name[1].TextString),
		 EMPTY (element->Name[2].TextString),
		 prec, UNIT (0.45 * element->Name[1].Scale * 100.),
		 prec, units(element->Name[1].X),
		 prec, units(element->Name[1].Y),
		 TEST_FLAG (HIDENAMEFLAG, element) ?
		 ",\n  but it's hidden" : "", prec, units(element->MarkX),
		 prec, units(element->MarkY),
		 TEST_FLAG (ONSOLDERFLAG, element) ? "solder (bottom)" :
		 "component", TEST_FLAG (LOCKFLAG, element) ?
		 "It is LOCKED.\n" : "");
	break;
      }
    case TEXT_TYPE:
#ifndef NDEBUG
      if (gui->shift_is_pressed ())
	{
	  LayerTypePtr layer = (LayerTypePtr) ptr1;
	  __r_dump_tree (layer->text_tree->root, 0);
	  return 0;
	}
#endif
    case ELEMENTNAME_TYPE:
      {
	char laynum[32];
	TextTypePtr text;
#ifndef NDEBUG
	if (gui->shift_is_pressed ())
	  {
	    __r_dump_tree (PCB->Data->name_tree[NAME_INDEX (PCB)]->root, 0);
	    return 0;
	  }
#endif
	text = (TextTypePtr) ptr2;

	if (type == TEXT_TYPE)
	  sprintf (laynum, "It is on layer %d.",
		   GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1));
	sprintf (&report[0], "TEXT ID# %ld;  Flags:%s\n"
		 "Located at (X,Y) = (%.*f,%.*f) %s.\n"
		 "Characters are %0.*f %s tall.\n"
		 "Value is \"%s\".\n"
		 "Direction is %d.\n"
		 "The bounding box is (%.*f,%.*f) (%.*f, %.*f) %s.\n"
		 "%s\n"
		 "%s", text->ID, flags_to_string (text->Flags, TEXT_TYPE),
		 prec, units(text->X), prec, UNIT (text->Y),
		 prec, UNIT (0.45 * text->Scale * 100.),
		 text->TextString, text->Direction,
		 prec, units(text->BoundingBox.X1),
		 prec, units(text->BoundingBox.Y1),
		 prec, units(text->BoundingBox.X2),
		 prec, UNIT (text->BoundingBox.Y2),
		 (type == TEXT_TYPE) ? laynum : "It is an element name.",
		 TEST_FLAG (LOCKFLAG, text) ? "It is LOCKED.\n" : "");
	break;
      }
    case LINEPOINT_TYPE:
    case POLYGONPOINT_TYPE:
      {
	PointTypePtr point = (PointTypePtr) ptr2;
	sprintf (&report[0], "POINT ID# %ld.\n"
		 "Located at (X,Y) = (%.*f,%.*f) %s.\n"
		 "It belongs to a %s on layer %d.\n", point->ID,
		 prec, units (point->X), prec, UNIT (point->Y),
		 (type == LINEPOINT_TYPE) ? "line" : "polygon",
		 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1));
	break;
      }
    case NO_TYPE:
      report[0] = '\0';
      break;

    default:
      sprintf (&report[0], "Unknown\n");
      break;
    }

  if (report[0] == '\0')
    {
      Message (_("Nothing found to report on\n"));
      return 1;
    }
  HideCrosshair (false);
  /* create dialog box */
  gui->report_dialog ("Report", &report[0]);

  RestoreCrosshair (false);
  return 0;
}
Ejemplo n.º 25
0
/* ---------------------------------------------------------------------------
 * copies data from one element to another and creates the destination 
 * if necessary
 */
ElementType *
CopyElementLowLevel (DataType *Data, ElementType *Src,
                     bool uniqueName, Coord dx, Coord dy, int mask_flags)
{
  int i;
  ElementType *Dest;

  /* both coordinates and flags are the same */
  Dest = CreateNewElement (Data, &PCB->Font,
			   MaskFlags (Src->Flags, mask_flags),
			   DESCRIPTION_NAME (Src), NAMEONPCB_NAME (Src),
			   VALUE_NAME (Src), DESCRIPTION_TEXT (Src).X + dx,
			   DESCRIPTION_TEXT (Src).Y + dy,
			   DESCRIPTION_TEXT (Src).Direction,
			   DESCRIPTION_TEXT (Src).Scale,
			   MaskFlags (DESCRIPTION_TEXT (Src).Flags,
				      mask_flags), uniqueName);

  /* abort on error */
  if (!Dest)
    return (Dest);

  ELEMENTLINE_LOOP (Src);
  {
    CreateNewLineInElement (Dest, line->Point1.X + dx,
			    line->Point1.Y + dy, line->Point2.X + dx,
			    line->Point2.Y + dy, line->Thickness);
  }
  END_LOOP;
  PIN_LOOP (Src);
  {
    CreateNewPin (Dest, pin->X + dx, pin->Y + dy, pin->Thickness,
		  pin->Clearance, pin->Mask, pin->DrillingHole,
		  pin->Name, pin->Number, MaskFlags (pin->Flags, mask_flags));
  }
  END_LOOP;
  PAD_LOOP (Src);
  {
    CreateNewPad (Dest, pad->Point1.X + dx, pad->Point1.Y + dy,
		  pad->Point2.X + dx, pad->Point2.Y + dy, pad->Thickness,
		  pad->Clearance, pad->Mask, pad->Name, pad->Number,
		  MaskFlags (pad->Flags, mask_flags));
  }
  END_LOOP;
  ARC_LOOP (Src);
  {
    CreateNewArcInElement (Dest, arc->X + dx, arc->Y + dy, arc->Width,
			   arc->Height, arc->StartAngle, arc->Delta,
			   arc->Thickness);
  }
  END_LOOP;

  for (i=0; i<Src->Attributes.Number; i++)
    CreateNewAttribute (& Dest->Attributes,
			Src->Attributes.List[i].name,
			Src->Attributes.List[i].value);

  Dest->MarkX = Src->MarkX + dx;
  Dest->MarkY = Src->MarkY + dy;

  SetElementBoundingBox (Data, Dest, &PCB->Font);
  return (Dest);
}
Ejemplo n.º 26
0
static int
PrintBOM (void)
{
  char utcTime[64];
  Coord x, y;
  double theta = 0.0;
  double sumx, sumy;
  int pinfound[MAXREFPINS];
  double pinx[MAXREFPINS];
  double piny[MAXREFPINS];
  double pinangle[MAXREFPINS];
  double padcentrex, padcentrey;
  double centroidx, centroidy;
  double pin1x, pin1y;
  int pin_cnt;
  int found_any_not_at_centroid;
  int found_any;
  time_t currenttime;
  FILE *fp;
  BomList *bom = NULL;
  char *name, *descr, *value,*fixed_rotation;
  int rpindex;

  fp = fopen (xy_filename, "w");
  if (!fp)
    {
      gui->log ("Cannot open file %s for writing\n", xy_filename);
      return 1;
    }

  /* Create a portable timestamp. */
  currenttime = time (NULL);
  {
    /* avoid gcc complaints */
    const char *fmt = "%c UTC";
    strftime (utcTime, sizeof (utcTime), fmt, gmtime (&currenttime));
  }
  fprintf (fp, "# PcbXY Version 1.0\n");
  fprintf (fp, "# Date: %s\n", utcTime);
  fprintf (fp, "# Author: %s\n", pcb_author ());
  fprintf (fp, "# Title: %s - PCB X-Y\n", UNKNOWN (PCB->Name));
  fprintf (fp, "# RefDes, Description, Value, X, Y, rotation, top/bottom\n");
  /* don't use localized xy_unit->in_suffix here since */
  /* the line itself is not localized and not for GUI  */
  fprintf (fp, "# X,Y in %s.  rotation in degrees.\n", xy_unit->suffix);
  fprintf (fp, "# --------------------------------------------\n");

  /*
   * For each element we calculate the centroid of the footprint.
   * In addition, we need to extract some notion of rotation.
   * While here generate the BOM list
   */

  ELEMENT_LOOP (PCB->Data);
  {

    /* Initialize our pin count and our totals for finding the centroid. */
    pin_cnt = 0;
    sumx = 0.0;
    sumy = 0.0;
    for (rpindex = 0; rpindex < MAXREFPINS; rpindex++)
      pinfound[rpindex] = 0;

    /* Insert this component into the bill of materials list. */
    bom = bom_insert ((char *)UNKNOWN (NAMEONPCB_NAME (element)),
                      (char *)UNKNOWN (DESCRIPTION_NAME (element)),
                      (char *)UNKNOWN (VALUE_NAME (element)), bom);


    /*
     * Iterate over the pins and pads keeping a running count of how
     * many pins/pads total and the sum of x and y coordinates
     *
     * While we're at it, store the location of pin/pad #1 and #2 if
     * we can find them.
     */

    PIN_LOOP (element);
    {
      sumx += (double) pin->X;
      sumy += (double) pin->Y;
      pin_cnt++;

      for (rpindex = 0; reference_pin_names[rpindex]; rpindex++)
        {
          if (NSTRCMP (pin->Number, reference_pin_names[rpindex]) == 0)
            {
                pinx[rpindex] = (double) pin->X;
                piny[rpindex] = (double) pin->Y;
                pinangle[rpindex] = 0.0; /* pins have no notion of angle */
                pinfound[rpindex] = 1;
            }
        }
    }
    END_LOOP;

    PAD_LOOP (element);
    {
      sumx += (pad->Point1.X + pad->Point2.X) / 2.0;
      sumy += (pad->Point1.Y + pad->Point2.Y) / 2.0;
      pin_cnt++;

      for (rpindex = 0; reference_pin_names[rpindex]; rpindex++)
        {
          if (NSTRCMP (pad->Number, reference_pin_names[rpindex]) == 0)
            {
              padcentrex = (double) (pad->Point1.X + pad->Point2.X) / 2.0;
              padcentrey = (double) (pad->Point1.Y + pad->Point2.Y) / 2.0;
              pinx[rpindex] = padcentrex;
              piny[rpindex] = padcentrey;
              /*
               * NOTE: We swap the Y points because in PCB, the Y-axis
               * is inverted.  Increasing Y moves down.  We want to deal
               * in the usual increasing Y moves up coordinates though.
               */
              pinangle[rpindex] = (180.0 / M_PI) * atan2 (pad->Point1.Y - pad->Point2.Y,
                pad->Point2.X - pad->Point1.X);
              pinfound[rpindex]=1;
            }
        }
    }
    END_LOOP;

    if (pin_cnt > 0)
      {
	centroidx = sumx / (double) pin_cnt;
	centroidy = sumy / (double) pin_cnt;
	      
	if (NSTRCMP( AttributeGetFromList (&element->Attributes,"xy-centre"), "origin") == 0 )
	  {
            x = element->MarkX;
            y = element->MarkY;
	  }
	else
	  {
            x = centroidx;
            y = centroidy;
	  }
	
	fixed_rotation = AttributeGetFromList (&element->Attributes, "xy-fixed-rotation");
	if (fixed_rotation)
	  {	
            /* The user specified a fixed rotation */
            theta = atof (fixed_rotation);
            found_any_not_at_centroid = 1;
            found_any = 1;
	  } 
	else
	  {
            /* Find first reference pin not at the  centroid  */
            found_any_not_at_centroid = 0;
            found_any = 0;
            theta = 0.0;
            for (rpindex = 0;
                 reference_pin_names[rpindex] && !found_any_not_at_centroid;
                 rpindex++)
              {
		if (pinfound[rpindex])
		  {
                    found_any = 1;

                    /* Recenter pin "#1" onto the axis which cross at the part
                       centroid */
                    pin1x = pinx[rpindex] - x;
                    pin1y = piny[rpindex] - y;

                    /* flip x, to reverse rotation for elements on back */
                    if (FRONT (element) != 1)
                        pin1x = -pin1x;

                    /* if only 1 pin, use pin 1's angle */
                    if (pin_cnt == 1)
                      {
                        theta = pinangle[rpindex];
                        found_any_not_at_centroid = 1;
                      }
                    else if ((pin1x != 0.0) || (pin1y != 0.0))
                      {
                        theta = xyToAngle (pin1x, pin1y, pin_cnt > 2);
                        found_any_not_at_centroid = 1;
                      }
                  }
              }

            if (!found_any)
              {
                Message
                  ("PrintBOM(): unable to figure out angle because I could\n"
                   "     not find a suitable reference pin of element %s\n"
                   "     Setting to %g degrees\n",
                   UNKNOWN (NAMEONPCB_NAME (element)), theta);
              }
            else if (!found_any_not_at_centroid)
              {
                Message
                      ("PrintBOM(): unable to figure out angle of element\n"
                       "     %s because the reference pin(s) are at the centroid of the part.\n"
                       "     Setting to %g degrees\n",
                       UNKNOWN (NAMEONPCB_NAME (element)), theta);
	      }
          }
	name = CleanBOMString ((char *)UNKNOWN (NAMEONPCB_NAME (element)));
	descr = CleanBOMString ((char *)UNKNOWN (DESCRIPTION_NAME (element)));
	value = CleanBOMString ((char *)UNKNOWN (VALUE_NAME (element)));

 	y = PCB->MaxHeight - y;
	pcb_fprintf (fp, "%m+%s,\"%s\",\"%s\",%.2mS,%.2mS,%g,%s\n",
		     xy_unit->allow, name, descr, value, x, y,
		     theta, FRONT (element) == 1 ? "top" : "bottom");
	free (name);
	free (descr);
	free (value);
      }
  }
  END_LOOP;

  fclose (fp);

  /* Now print out a Bill of Materials file */

  fp = fopen (bom_filename, "w");
  if (!fp)
    {
      gui->log ("Cannot open file %s for writing\n", bom_filename);
      print_and_free (NULL, bom);
      return 1;
    }

  fprintf (fp, "# PcbBOM Version 1.0\n");
  fprintf (fp, "# Date: %s\n", utcTime);
  fprintf (fp, "# Author: %s\n", pcb_author ());
  fprintf (fp, "# Title: %s - PCB BOM\n", UNKNOWN (PCB->Name));
  fprintf (fp, "# Quantity, Description, Value, RefDes\n");
  fprintf (fp, "# --------------------------------------------\n");

  print_and_free (fp, bom);

  fclose (fp);

  return (0);
}
Ejemplo n.º 27
0
static void
pinout_set_data (GhidPinoutPreview * pinout, ElementType * element)
{
  gint tx, ty, x_min = 0, y_min = 0;

  if (element == NULL)
    {
      FreeElementMemory (&pinout->element);
      pinout->w_pixels = 0;
      pinout->h_pixels = 0;
      return;
    }

  /* 
   * copy element data 
   * enable output of pin and padnames
   * move element to a 5% offset from zero position
   * set all package lines/arcs to zero width
   */
  CopyElementLowLevel (NULL, &pinout->element, element, FALSE, 0, 0);
  PIN_LOOP (&pinout->element);
  {
    tx = abs (pinout->element.Pin[0].X - pin->X);
    ty = abs (pinout->element.Pin[0].Y - pin->Y);
    if (x_min == 0 || (tx != 0 && tx < x_min))
      x_min = tx;
    if (y_min == 0 || (ty != 0 && ty < y_min))
      y_min = ty;
    SET_FLAG (DISPLAYNAMEFLAG, pin);
  }
  END_LOOP;

  PAD_LOOP (&pinout->element);
  {
    tx = abs (pinout->element.Pad[0].Point1.X - pad->Point1.X);
    ty = abs (pinout->element.Pad[0].Point1.Y - pad->Point1.Y);
    if (x_min == 0 || (tx != 0 && tx < x_min))
      x_min = tx;
    if (y_min == 0 || (ty != 0 && ty < y_min))
      y_min = ty;
    SET_FLAG (DISPLAYNAMEFLAG, pad);
  }
  END_LOOP;


  MoveElementLowLevel (NULL, &pinout->element,
		       Settings.PinoutOffsetX -
		       pinout->element.BoundingBox.X1,
		       Settings.PinoutOffsetY -
		       pinout->element.BoundingBox.Y1);

  if (!pinout_zoom_fit (pinout, 2))
    pinout_zoom_fit (pinout, 3);

  ELEMENTLINE_LOOP (&pinout->element);
  {
    line->Thickness = 0;
  }
  END_LOOP;

  ARC_LOOP (&pinout->element);
  {
    /* 
     * for whatever reason setting a thickness of 0 causes the arcs to
     * not display so pick 1 which does display but is still quite
     * thin.
     */
    arc->Thickness = 1;
  }
  END_LOOP;
}
Ejemplo n.º 28
0
/* ---------------------------------------------------------------------------
 * searches for a object by it's unique ID. It doesn't matter if
 * the object is visible or not. The search is performed on a PCB, a
 * buffer or on the remove list.
 * The calling routine passes two pointers to allocated memory for storing
 * the results. 
 * A type value is returned too which is NO_TYPE if no objects has been found.
 */
int
SearchObjectByID (DataTypePtr Base,
		  void **Result1, void **Result2, void **Result3, int ID,
		  int type)
{
  if (type == LINE_TYPE || type == LINEPOINT_TYPE)
    {
      ALLLINE_LOOP (Base);
      {
	if (line->ID == ID)
	  {
	    *Result1 = (void *) layer;
	    *Result2 = *Result3 = (void *) line;
	    return (LINE_TYPE);
	  }
	if (line->Point1.ID == ID)
	  {
	    *Result1 = (void *) layer;
	    *Result2 = (void *) line;
	    *Result3 = (void *) &line->Point1;
	    return (LINEPOINT_TYPE);
	  }
	if (line->Point2.ID == ID)
	  {
	    *Result1 = (void *) layer;
	    *Result2 = (void *) line;
	    *Result3 = (void *) &line->Point2;
	    return (LINEPOINT_TYPE);
	  }
      }
      ENDALL_LOOP;
    }
  if (type == ARC_TYPE)
    {
      ALLARC_LOOP (Base);
      {
	if (arc->ID == ID)
	  {
	    *Result1 = (void *) layer;
	    *Result2 = *Result3 = (void *) arc;
	    return (ARC_TYPE);
	  }
      }
      ENDALL_LOOP;
    }

  if (type == TEXT_TYPE)
    {
      ALLTEXT_LOOP (Base);
      {
	if (text->ID == ID)
	  {
	    *Result1 = (void *) layer;
	    *Result2 = *Result3 = (void *) text;
	    return (TEXT_TYPE);
	  }
      }
      ENDALL_LOOP;
    }

  if (type == POLYGON_TYPE || type == POLYGONPOINT_TYPE)
    {
      ALLPOLYGON_LOOP (Base);
      {
	if (polygon->ID == ID)
	  {
	    *Result1 = (void *) layer;
	    *Result2 = *Result3 = (void *) polygon;
	    return (POLYGON_TYPE);
	  }
	if (type == POLYGONPOINT_TYPE)
	  POLYGONPOINT_LOOP (polygon);
	{
	  if (point->ID == ID)
	    {
	      *Result1 = (void *) layer;
	      *Result2 = (void *) polygon;
	      *Result3 = (void *) point;
	      return (POLYGONPOINT_TYPE);
	    }
	}
	END_LOOP;
      }
      ENDALL_LOOP;
    }
  if (type == VIA_TYPE)
    {
      VIA_LOOP (Base);
      {
	if (via->ID == ID)
	  {
	    *Result1 = *Result2 = *Result3 = (void *) via;
	    return (VIA_TYPE);
	  }
      }
      END_LOOP;
    }

  if (type == RATLINE_TYPE || type == LINEPOINT_TYPE)
    {
      RAT_LOOP (Base);
      {
	if (line->ID == ID)
	  {
	    *Result1 = *Result2 = *Result3 = (void *) line;
	    return (RATLINE_TYPE);
	  }
	if (line->Point1.ID == ID)
	  {
	    *Result1 = (void *) NULL;
	    *Result2 = (void *) line;
	    *Result3 = (void *) &line->Point1;
	    return (LINEPOINT_TYPE);
	  }
	if (line->Point2.ID == ID)
	  {
	    *Result1 = (void *) NULL;
	    *Result2 = (void *) line;
	    *Result3 = (void *) &line->Point2;
	    return (LINEPOINT_TYPE);
	  }
      }
      END_LOOP;
    }

  if (type == ELEMENT_TYPE || type == PAD_TYPE || type == PIN_TYPE
      || type == ELEMENTLINE_TYPE || type == ELEMENTNAME_TYPE
      || type == ELEMENTARC_TYPE)
    /* check pins and elementnames too */
    ELEMENT_LOOP (Base);
  {
    if (element->ID == ID)
      {
	*Result1 = *Result2 = *Result3 = (void *) element;
	return (ELEMENT_TYPE);
      }
    if (type == ELEMENTLINE_TYPE)
      ELEMENTLINE_LOOP (element);
    {
      if (line->ID == ID)
	{
	  *Result1 = (void *) element;
	  *Result2 = *Result3 = (void *) line;
	  return (ELEMENTLINE_TYPE);
	}
    }
    END_LOOP;
    if (type == ELEMENTARC_TYPE)
      ARC_LOOP (element);
    {
      if (arc->ID == ID)
	{
	  *Result1 = (void *) element;
	  *Result2 = *Result3 = (void *) arc;
	  return (ELEMENTARC_TYPE);
	}
    }
    END_LOOP;
    if (type == ELEMENTNAME_TYPE)
      ELEMENTTEXT_LOOP (element);
    {
      if (text->ID == ID)
	{
	  *Result1 = (void *) element;
	  *Result2 = *Result3 = (void *) text;
	  return (ELEMENTNAME_TYPE);
	}
    }
    END_LOOP;
    if (type == PIN_TYPE)
      PIN_LOOP (element);
    {
      if (pin->ID == ID)
	{
	  *Result1 = (void *) element;
	  *Result2 = *Result3 = (void *) pin;
	  return (PIN_TYPE);
	}
    }
    END_LOOP;
    if (type == PAD_TYPE)
      PAD_LOOP (element);
    {
      if (pad->ID == ID)
	{
	  *Result1 = (void *) element;
	  *Result2 = *Result3 = (void *) pad;
	  return (PAD_TYPE);
	}
    }
    END_LOOP;
  }
  END_LOOP;

  Message ("hace: Internal error, search for ID %d failed\n", ID);
  return (NO_TYPE);
}
Ejemplo n.º 29
0
/* ---------------------------------------------------------------------------
 * moves a element by +-X and +-Y
 */
void
MoveElementLowLevel (DataTypePtr Data, ElementTypePtr Element,
		     Coord DX, Coord DY)
{
  if (Data)
    r_delete_entry (Data->element_tree, (BoxType *)Element);
  ELEMENTLINE_LOOP (Element);
  {
    MOVE_LINE_LOWLEVEL (line, DX, DY);
  }
  END_LOOP;
  PIN_LOOP (Element);
  {
    if (Data)
      {
	r_delete_entry (Data->pin_tree, (BoxType *)pin);
	RestoreToPolygon (Data, PIN_TYPE, Element, pin);
      }
    MOVE_PIN_LOWLEVEL (pin, DX, DY);
    if (Data)
      {
	r_insert_entry (Data->pin_tree, (BoxType *)pin, 0);
	ClearFromPolygon (Data, PIN_TYPE, Element, pin);
      }
  }
  END_LOOP;
  PAD_LOOP (Element);
  {
    if (Data)
      {
	r_delete_entry (Data->pad_tree, (BoxType *)pad);
	RestoreToPolygon (Data, PAD_TYPE, Element, pad);
      }
    MOVE_PAD_LOWLEVEL (pad, DX, DY);
    if (Data)
      {
	r_insert_entry (Data->pad_tree, (BoxType *)pad, 0);
	ClearFromPolygon (Data, PAD_TYPE, Element, pad);
      }
  }
  END_LOOP;
  ARC_LOOP (Element);
  {
    MOVE_ARC_LOWLEVEL (arc, DX, DY);
  }
  END_LOOP;
  ELEMENTTEXT_LOOP (Element);
  {
    if (Data && Data->name_tree[n])
      r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text);
    MOVE_TEXT_LOWLEVEL (text, DX, DY);
    if (Data && Data->name_tree[n])
      r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0);
  }
  END_LOOP;
  MOVE_BOX_LOWLEVEL (&Element->BoundingBox, DX, DY);
  MOVE_BOX_LOWLEVEL (&Element->VBox, DX, DY);
  MOVE (Element->MarkX, Element->MarkY, DX, DY);
  if (Data)
    r_insert_entry (Data->element_tree, (BoxType *)Element, 0);
}
Ejemplo n.º 30
0
Archivo: report.c Proyecto: thequux/pcb
static int
ReportAllNetLengths (int argc, char **argv, int x, int y)
{
  int ni;
  int found;
  double length;
  int prec;
  double scale;
  const char *units_name;

  units_name = argv[0];
  if (argc < 1)
    units_name = Settings.grid_units_mm ? "mm" : "mil";

  if (strcasecmp (units_name, "mm") == 0)
    {
      prec = 4;
      scale = COOR_TO_MM;
    }
  else if (strcasecmp (units_name, "mil") == 0)
    {
      prec = 2;
      scale = .01;
    }
  else if (strcasecmp (units_name, "in") == 0)
    {
      prec = 5;
      scale = 1./100000;
    }
  else
    {
      prec = 0;
      units_name = "pcb";
      scale = 1;
    }

  for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++)
    {
      char *netname = PCB->NetlistLib.Menu[ni].Name + 2;
      char *ename = PCB->NetlistLib.Menu[ni].Entry[0].ListEntry;
      char *pname;

      ename = strdup (ename);
      pname = strchr (ename, '-');
      if (! pname)
	{
	  free (ename);
	  continue;
	}
      *pname++ = 0;

      ELEMENT_LOOP (PCB->Data);
      {
	char *es = element->Name[NAMEONPCB_INDEX].TextString;
	if (es && strcmp (es, ename) == 0)
	  {
	    PIN_LOOP (element);
	    {
	      if (strcmp (pin->Number, pname) == 0)
		{
		  x = pin->X;
		  y = pin->Y;
		  goto got_one;
		}
	    }
	    END_LOOP;
	    PAD_LOOP (element);
	    {
	      if (strcmp (pad->Number, pname) == 0)
		{
		  x = (pad->Point1.X + pad->Point2.X) / 2;
		  y = (pad->Point1.Y + pad->Point2.Y) / 2;
		  goto got_one;
		}
	    }
	    END_LOOP;
	  }
      }
      END_LOOP;

      continue;

    got_one:
      if (ResetConnections (true))
        Draw ();
      /* NB: XYtoNetLength calls LookupConnection, which performs an undo
       *     serial number update, so we don't need to add one here.
       */
      length = XYtoNetLength (x, y, &found);

      gui->log("Net %s length %.*f %s\n", netname, prec, length*scale, units_name);
    }
  return 0;
}