예제 #1
0
/*!
 * \brief Locking all or selected elements.
 *
 * Usage:\n
 * UnlockElements(All)\n
 * UE(All)\n       
 * If no argument is passed, no action is carried out.
 */
static int
unlock_elements (int argc, char **argv, Coord x, Coord y)
{
        int all = 0;
        if (strcasecmp (argv[0], "All") == 0)
                all = 1;
        else
        {
                Message ("ERROR: in UnlockElements argument should be All.\n");
                return 1;
        }
        SET_FLAG (NAMEONPCBFLAG, PCB);
        ELEMENT_LOOP(PCB->Data);
        {
                if (TEST_FLAG (LOCKFLAG, element))
                {
                        /* element is locked */
                        if (all)
                                CLEAR_FLAG(LOCKFLAG, element);
                }
        }
        END_LOOP;
        gui->invalidate_all ();
        IncrementUndoSerialNumber ();
        return 0;
}
예제 #2
0
/*!
 * \brief Find the specified element.
 *
 * Usage: FindElement(Refdes)\n
 * If no argument is passed, no action is carried out.
 */
static int
find_element (int argc, char **argv, Coord x, Coord y)
{
  if (argc == 0 || strcasecmp (argv[0], "") == 0)
  {
    Message ("WARNING: in FindElement the argument should be a non-empty string value.\n");
      return 0;
  }
  else
  {
    SET_FLAG (NAMEONPCBFLAG, PCB);
    ELEMENT_LOOP(PCB->Data);
    {
      if (NAMEONPCB_NAME(element)
        && strcmp (argv[0], NAMEONPCB_NAME(element)) == 0)
      {
        gui->set_crosshair
        (
          element->MarkX,
          element->MarkY,
          HID_SC_PAN_VIEWPORT
        );
      }
    }
    END_LOOP;
    gui->invalidate_all ();
    IncrementUndoSerialNumber ();
    return 0;
  };
}
예제 #3
0
int
footprint_update(int argc, char **argv, int x, int y)
{
  global_argc = argc;
  global_argv = argv;

  debug_log("footprint_update\n");
  debug_log("  argc: %d\n", argc);
  if (argc) {
    int i;
    for (i = 0; i < argc; i++) {
      debug_log("  argv[%d]: %s\n", i, argv[i]);
    }
  }
  if (argc >= 1) {
    if (strcasecmp(argv[0], "auto") == 0) {
      match_mode = MATCH_MODE_AUTO;
      style = STYLE_ALL;
    } else if (strcasecmp(argv[0], "manual") == 0) {
      match_mode = MATCH_MODE_MANUAL;
      style = STYLE_SELECTED;
    } else {
      base_log("Error: If given, the first argument must be "
               "\"auto\" or \"manual\".\n");
      return usage();
    }
    if (argc >= 2) {
      if (strcasecmp(argv[1], "selected") == 0) {
        style = STYLE_SELECTED;
      } else if (strcasecmp(argv[1], "named") == 0) {
        style = STYLE_NAMED;
      } else {
        base_log("Error: If given, the second argument must be "
                 "\"selected\", or \"named\".\n");
        return usage();
      }
    }
    
  }
  debug_log("match_mode: %d\n", match_mode);
  debug_log("style: %d\n", style);

  if (PASTEBUFFER->Data->ElementN != 1) {
    base_log("Error: Paste buffer should contain one element.\n");
    return usage();
  }

  ELEMENT_LOOP(PASTEBUFFER->Data);
  {
    int replaced = replace_footprints(element);
    if (replaced) {
      base_log("Replaced %d elements.\n", replaced);
      IncrementUndoSerialNumber();
    }
  }
  END_LOOP;

  return 0;
}
예제 #4
0
파일: buffer.c 프로젝트: bgamari/geda-pcb
/* ---------------------------------------------------------------------------
 * rotates the contents of the pastebuffer
 */
void
RotateBuffer (BufferType *Buffer, BYTE Number)
{
  /* rotate vias */
  VIA_LOOP (Buffer->Data);
  {
    r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
    ROTATE_VIA_LOWLEVEL (via, Buffer->X, Buffer->Y, Number);
    SetPinBoundingBox (via);
    r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
  }
  END_LOOP;

  /* elements */
  ELEMENT_LOOP (Buffer->Data);
  {
    RotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
			   Number);
  }
  END_LOOP;

  /* all layer related objects */
  ALLLINE_LOOP (Buffer->Data);
  {
    r_delete_entry (layer->line_tree, (BoxType *)line);
    RotateLineLowLevel (line, Buffer->X, Buffer->Y, Number);
    r_insert_entry (layer->line_tree, (BoxType *)line, 0);
  }
  ENDALL_LOOP;
  ALLARC_LOOP (Buffer->Data);
  {
    r_delete_entry (layer->arc_tree, (BoxType *)arc);
    RotateArcLowLevel (arc, Buffer->X, Buffer->Y, Number);
    r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
  }
  ENDALL_LOOP;
  ALLTEXT_LOOP (Buffer->Data);
  {
    r_delete_entry (layer->text_tree, (BoxType *)text);
    RotateTextLowLevel (text, Buffer->X, Buffer->Y, Number);
    r_insert_entry (layer->text_tree, (BoxType *)text, 0);
  }
  ENDALL_LOOP;
  ALLPOLYGON_LOOP (Buffer->Data);
  {
    r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
    RotatePolygonLowLevel (polygon, Buffer->X, Buffer->Y, Number);
    r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
  }
  ENDALL_LOOP;

  /* finally the origin and the bounding box */
  ROTATE (Buffer->X, Buffer->Y, Buffer->X, Buffer->Y, Number);
  RotateBoxLowLevel (&Buffer->BoundingBox, Buffer->X, Buffer->Y, Number);
  SetCrosshairRangeToBuffer ();
}
예제 #5
0
int
IPCD356_SanityCheck()
{
  ELEMENT_LOOP (PCB->Data);
    if (element->Name[1].TextString == '\0')
      {
        Message("Error: Found unnamed element. All elements need to be named to create an IPC-D-356 netlist.\n");
        return(1);
      }
  END_LOOP; /* Element. */
  return(0);
}
예제 #6
0
/*
 * Find all selected objects, then order them in order by coordinate in
 * the 'dir' axis.  This is used to find the "First" and "Last" elements
 * and also to choose the distribution order.
 *
 * For alignment, first and last are in the orthogonal axis (imagine if
 * you were lining up letters in a sentence, aligning *vertically* to the
 * first letter means selecting the first letter *horizontally*).
 *
 * For distribution, first and last are in the distribution axis.
 */
static int
sort_elements_by_pos(int op, int dir, int point)
{
	int nsel = 0;

	if (nelements_by_pos)
		return nelements_by_pos;

	if (op == K_align)
		dir = dir == K_X ? K_Y : K_X;	/* see above */

	ELEMENT_LOOP(PCB->Data);
	{
		if (! TEST_FLAG (SELECTEDFLAG, element))
			continue;
		nsel++;
	}
	END_LOOP;

	if (! nsel)
		return 0;

	elements_by_pos = malloc(nsel * sizeof(*elements_by_pos));
	nelements_by_pos = nsel;

	nsel = 0;
	ELEMENT_LOOP(PCB->Data);
	{
		if (! TEST_FLAG (SELECTEDFLAG, element))
			continue;
		elements_by_pos[nsel].element = element;
		elements_by_pos[nsel++].pos = coord(element, dir, point);
	}
	END_LOOP;

	qsort(elements_by_pos, nelements_by_pos,
		sizeof(*elements_by_pos), cmp_ebp);
	return nelements_by_pos;
}
예제 #7
0
파일: mymem.c 프로젝트: bert/pcb-update
/* ---------------------------------------------------------------------------
 * 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++);
}
예제 #8
0
파일: autoplace.c 프로젝트: bert/pcb-update
/* ---------------------------------------------------------------------------
 * Create a list of selected elements.
 */
static PointerListType
collectSelectedElements ()
{
  PointerListType list = { 0, 0, NULL };
  ELEMENT_LOOP (PCB->Data);
  {
    if (TEST_FLAG (SELECTEDFLAG, element))
      {
	ElementTypePtr *epp = (ElementTypePtr *) GetPointerMemory (&list);
	*epp = element;
      }
  }
  END_LOOP;
  return list;
}
예제 #9
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. */
}
예제 #10
0
파일: netlist.c 프로젝트: bert/pcb-rnd
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);
}
예제 #11
0
static int
replace_footprints(ElementTypePtr new_element)
{
  int replaced = 0;
  int i = 0;

  ELEMENT_LOOP (PCB->Data);
  {
    if (match_mode != MATCH_MODE_AUTO
        || strcmp(DESCRIPTION_NAME(new_element),
                  DESCRIPTION_NAME(element)) == 0) {
      Boolean matched = False;

      switch (style) {
      case STYLE_ALL:
        matched = True;
        break;
      case STYLE_SELECTED:
        matched = TEST_FLAG(SELECTEDFLAG, element);
        break;
      case STYLE_NAMED:
        for (i = 0; i < global_argc; i++) {
          if (NAMEONPCB_NAME(element)
              && strcasecmp(NAMEONPCB_NAME(element), global_argv[i]) == 0) {
            matched = True;
            break;
          }
        }
        break;
      }
      if (matched) {
        if (TEST_FLAG (LOCKFLAG, element)) {
          base_log("Skipping \"%s\".  Element locked.\n",
                   NAMEONPCB_NAME(element));
        } else {
          debug_log("Considering \"%s\".\n", NAMEONPCB_NAME(element));
          if (replace_one_footprint(element, new_element)) {
            base_log("Replaced \"%s\".\n", NAMEONPCB_NAME(element));
            replaced++;
          }
        }
      }
    }
  }
  END_LOOP;
  return replaced;
}
예제 #12
0
static int
renumber_block (int argc, char **argv, Coord x, Coord y)
{
  char num_buf[15];
  int old_base, new_base;

  if (argc < 2) {
    Message("Usage: RenumberBlock oldnum newnum");
    return 1;
  }

  old_base = atoi (argv[0]);
  new_base = atoi (argv[1]);

  SET_FLAG (NAMEONPCBFLAG, PCB);

  ELEMENT_LOOP (PCB->Data);
  {
    char *refdes_split, *cp;
    char *old_ref, *new_ref;
    int num;

    if (!TEST_FLAG (SELECTEDFLAG, element))
      continue;

    old_ref = element->Name[1].TextString;
    for (refdes_split=cp=old_ref; *cp; cp++)
      if (!isdigit(*cp))
        refdes_split = cp+1;

    num = atoi (refdes_split);
    num += (new_base - old_base);
    sprintf(num_buf, "%d" ,num);
    new_ref = (char *) malloc (refdes_split - old_ref + strlen(num_buf) + 1);
    memcpy (new_ref, old_ref, refdes_split - old_ref);
    strcpy (new_ref + (refdes_split - old_ref), num_buf);

    AddObjectToChangeNameUndoList (ELEMENT_TYPE, NULL, NULL,
                                   element,
                                   NAMEONPCB_NAME (element));

    ChangeObjectName (ELEMENT_TYPE, element, NULL, NULL, new_ref);
  }
  END_LOOP;
  IncrementUndoSerialNumber ();
  return 0;
}
예제 #13
0
/* find the reference coordinate from the specified points of all selected elements */
static Coord
reference_coord(int op, int x, int y, int dir, int point, int reference)
{
	Coord q;
	int nsel;

	q = 0;
	switch (reference) {
	case K_Crosshair:
		if (dir == K_X)
			q = x;
		else
			q = y;
		break;

	case K_Average:		/* the average among selected elements */
		nsel = 0;
		q = 0;
		ELEMENT_LOOP(PCB->Data);
		{
			if (! TEST_FLAG (SELECTEDFLAG, element))
				continue;
			q += coord(element, dir, point);
			nsel++;
		}
		END_LOOP;
		if (nsel)
			q /= nsel;
		break;

	case K_First:		/* first or last in the orthogonal direction */
	case K_Last:
		if (! sort_elements_by_pos(op, dir, point)) {
			q = 0;
			break;
		}
		if (reference == K_First) {
			q = coord(elements_by_pos[0].element,
				dir, point);
		} else {
			q = coord(elements_by_pos[nelements_by_pos-1].element,
				dir, point);
		}
		break;
	}
	return q;
}
예제 #14
0
파일: search.c 프로젝트: bert/pcb-rnd
/* ---------------------------------------------------------------------------
 * searches for an element by its board name.
 * The function returns a pointer to the element, NULL if not found
 */
ElementTypePtr
SearchElementByName (DataTypePtr Base, char *Name)
{
  ElementTypePtr result = NULL;

  ELEMENT_LOOP (Base);
  {
    if (element->Name[1].TextString &&
	NSTRCMP (element->Name[1].TextString, Name) == 0)
      {
	result = element;
	return (result);
      }
  }
  END_LOOP;
  return result;
}
예제 #15
0
파일: autocrop.c 프로젝트: bert/pcb-plugins
/*!
 * \brief Move everything.
 *
 * Call our own 'MyMove*LowLevel' where they don't exist in move.c.
 * This gets very slow if there are large polygons present, since every
 * element move re-clears the poly, followed by the polys moving and
 * re-clearing everything again.
 */
static void
MoveAll(Coord dx, Coord dy)
{
  ELEMENT_LOOP (PCB->Data);
  {
    MoveElementLowLevel (PCB->Data, element, dx, dy);
    AddObjectToMoveUndoList (ELEMENT_TYPE, NULL, NULL, element, dx, dy);
  }
  END_LOOP;
  VIA_LOOP (PCB->Data);
  {
    MyMoveViaLowLevel (PCB->Data, via, dx, dy);
    AddObjectToMoveUndoList (VIA_TYPE, NULL, NULL, via, dx, dy);
  }
  END_LOOP;
  ALLLINE_LOOP (PCB->Data);
  {
    MyMoveLineLowLevel (PCB->Data, layer, line, dx, dy);
    AddObjectToMoveUndoList (LINE_TYPE, NULL, NULL, line, dx, dy);
  }
  ENDALL_LOOP;
  ALLARC_LOOP (PCB->Data);
  {
    MyMoveArcLowLevel (PCB->Data, layer, arc, dx, dy);
    AddObjectToMoveUndoList (ARC_TYPE, NULL, NULL, arc, dx, dy);
  }
  ENDALL_LOOP;
  ALLTEXT_LOOP (PCB->Data);
  {
    MyMoveTextLowLevel (layer, text, dx, dy);
    AddObjectToMoveUndoList (TEXT_TYPE, NULL, NULL, text, dx, dy);
  }
  ENDALL_LOOP;
  ALLPOLYGON_LOOP (PCB->Data);
  {
    /*
     * XXX MovePolygonLowLevel does not mean "no gui" like
     * XXX MoveElementLowLevel, it doesn't even handle layer
     * XXX tree activity.
     */
    MyMovePolygonLowLevel (PCB->Data, layer, polygon, dx, dy);
    AddObjectToMoveUndoList (POLYGON_TYPE, NULL, NULL, polygon, dx, dy);
  }
  ENDALL_LOOP;
}
예제 #16
0
파일: report.c 프로젝트: 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;
}
예제 #17
0
static int
renumber_buffer (int argc, char **argv, Coord x, Coord y)
{
  char num_buf[15];
  int old_base, new_base;

  if (argc < 2) {
    Message("Usage: RenumberBuffer oldnum newnum");
    return 1;
  }

  old_base = atoi (argv[0]);
  new_base = atoi (argv[1]);

  SET_FLAG (NAMEONPCBFLAG, PCB);

  ELEMENT_LOOP (PASTEBUFFER->Data);
  {
    char *refdes_split, *cp;
    char *old_ref, *new_ref;
    int num;

    old_ref = element->Name[1].TextString;
    for (refdes_split=cp=old_ref; *cp; cp++)
      if (!isdigit(*cp))
        refdes_split = cp+1;

    num = atoi (refdes_split);
    num += (new_base - old_base);
    sprintf(num_buf, "%d" ,num);
    new_ref = (char *) malloc (refdes_split - old_ref + strlen(num_buf) + 1);
    memcpy (new_ref, old_ref, refdes_split - old_ref);
    strcpy (new_ref + (refdes_split - old_ref), num_buf);

    ChangeObjectName (ELEMENT_TYPE, element, NULL, NULL, new_ref);
  }
  END_LOOP;
  return 0;
}
예제 #18
0
/*!
 * \brief Locking all or selected elements.
 *
 * Usage:\n
 * LockElements([Selected|All])\n
 * LE([Selected|All])\n
 * If no argument is passed, no action is carried out.
 */
static int
lock_elements (int argc, char **argv, Coord x, Coord y)
{
        int selected = 0;
        int all = 0;
        if (argc > 0 && strcasecmp (argv[0], "Selected") == 0)
                selected = 1;
        else if (argc >0 && strcasecmp (argv[0], "All") == 0)
                all = 1;
        else
        {
                Message ("ERROR: in LockElements argument should be either Selected or All.\n");
                return 1;
        }
        SET_FLAG (NAMEONPCBFLAG, PCB);
        ELEMENT_LOOP(PCB->Data);
        {
                if (!TEST_FLAG (LOCKFLAG, element))
                {
                        /* element is not locked */
                        if (all)
                                SET_FLAG(LOCKFLAG, element);
                        if (selected)
                        {
                                if (TEST_FLAG (SELECTEDFLAG, element))
                                {
                                        /* better to unselect element first */
                                        CLEAR_FLAG(SELECTEDFLAG, element);
                                        SET_FLAG(LOCKFLAG, element);
                                }
                        }
                }
        }
        END_LOOP;
        gui->invalidate_all ();
        IncrementUndoSerialNumber ();
        return 0;
}
예제 #19
0
/*
 * Find all selected text objects, then order them in order by coordinate in
 * the 'dir' axis.  This is used to find the "First" and "Last" elements
 * and also to choose the distribution order.
 *
 * For alignment, first and last are in the orthogonal axis (imagine if
 * you were lining up letters in a sentence, aligning *vertically* to the
 * first letter means selecting the first letter *horizontally*).
 *
 * For distribution, first and last are in the distribution axis.
 */
static int
sort_texts_by_pos(int op, int dir, int point)
{
	int nsel = 0;

	if (ntexts_by_pos)
		return ntexts_by_pos;

	if (op == K_aligntext)
		dir = dir == K_X ? K_Y : K_X;	/* see above */

	ELEMENT_LOOP(PCB->Data);
	{
		TextType *text;
		text = &(element)->Name[NAME_INDEX(PCB)];
		if (! TEST_FLAG (SELECTEDFLAG, text))
			continue;
		nsel++;
	}
	END_LOOP;


	ALLTEXT_LOOP (PCB->Data);
	{
		if (! TEST_FLAG (SELECTEDFLAG, text))
			continue;
		nsel++;
	}
	ENDALL_LOOP;


	if (! nsel)
		return 0;

	texts_by_pos = malloc(nsel * sizeof(*texts_by_pos));
	ntexts_by_pos = nsel;


	nsel = 0;

	ELEMENT_LOOP(PCB->Data);
	{
		TextType *text;
		text = &(element)->Name[NAME_INDEX(PCB)];
		if (! TEST_FLAG (SELECTEDFLAG, text))
			continue;
		texts_by_pos[nsel].text = text;
		texts_by_pos[nsel].type = ELEMENTNAME_TYPE;
		texts_by_pos[nsel++].pos = coord(text, dir, point);
	}
	END_LOOP;


	ALLTEXT_LOOP (PCB->Data);
	{
		if (! TEST_FLAG (SELECTEDFLAG, text))
			continue;
		texts_by_pos[nsel].text = text;
		texts_by_pos[nsel].type = TEXT_TYPE;
		texts_by_pos[nsel++].pos = coord(text, dir, point);
	}
	ENDALL_LOOP;


	qsort(texts_by_pos, ntexts_by_pos,
		sizeof(*texts_by_pos), cmp_tbp);
	return ntexts_by_pos;
}
예제 #20
0
파일: search.c 프로젝트: bert/pcb-rnd
/* ---------------------------------------------------------------------------
 * 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);
}
예제 #21
0
파일: report.c 프로젝트: 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;
}
예제 #22
0
파일: report.c 프로젝트: 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;
}
예제 #23
0
파일: smartdisperse.c 프로젝트: rlutz/pcb
/* %start-doc actions SmartDisperse

The @code{SmartDisperse([All|Selected])} action is a special-purpose
optimization for dispersing elements.

Run with @code{:SmartDisperse()} or @code{:SmartDisperse(Selected)}
(you can also say @code{:SmartDisperse(All)}, but that's the default).

%end-doc */
static int
smartdisperse (int argc, char **argv, Coord x, Coord y)
{
  char *function = ARG(0);
  NetListType *Nets;
  char *visited;
//  PointerListType stack = { 0, 0, NULL };
  int all;
//  int changed = 0;
//  int i;

  if (! function)
  {
    all = 1;
  }
  else if (strcmp(function, "All") == 0)
  {
    all = 1;
  }
  else if (strcmp(function, "Selected") == 0)
  {
    all = 0;
  }
  else
  {
    AFAIL (smartdisperse);
  }

  Nets = ProcNetlist (&PCB->NetlistLib);
  if (! Nets)
  {
    Message (_("Can't use SmartDisperse because no netlist is loaded.\n"));
    return 0;
  }

  /* remember which elements we finish with */
  visited = calloc (PCB->Data->ElementN, sizeof(*visited));

  /* if we're not doing all, mark the unselected elements as "visited" */
  ELEMENT_LOOP (PCB->Data);
  {
    if (! (all || TEST_FLAG (SELECTEDFLAG, element)))
    {
      visited[n] = 1;
    }
  }
  END_LOOP;

  /* initialize variables for place() */
  minx = GAP;
  miny = GAP;
  maxx = GAP;
  maxy = GAP;

  /*
   * Pick nets with two connections.  This is the start of a more
   * elaborate algorithm to walk serial nets, but the datastructures
   * are too gross so I'm going with the 80% solution.
   */
  NET_LOOP (Nets);
  {
    ConnectionType *conna, *connb;
    ElementType *ea, *eb;
//    ElementType *epp;

    if (net->ConnectionN != 2)
      continue;

    conna = &net->Connection[0];
    connb = &net->Connection[1];
    if (!IS_ELEMENT(conna) || !IS_ELEMENT(conna))
      continue;

    ea = (ElementType *) conna->ptr1;
    eb = (ElementType *) connb->ptr1;

    /* place this pair if possible */
    if (VISITED((GList *)ea) || VISITED((GList *)eb))
      continue;
    VISITED ((GList *)ea) = 1;
    VISITED ((GList *)eb) = 1;

    /* a weak attempt to get the linked pads side-by-side */
    if (padorder(conna, connb))
    {
      place ((ElementType *) ea);
      place ((ElementType *) eb);
    }
    else
    {
      place (eb);
      place (ea);
    }
  }
  END_LOOP;

  /* Place larger nets, still grouping by net */
  NET_LOOP (Nets);
  {
    CONNECTION_LOOP (net);
    {
      ElementType *element;

      if (! IS_ELEMENT(connection))
        continue;

      element = (ElementType *) connection->ptr1;

      /* place this one if needed */
      if (VISITED ((GList *) element))
        continue;
      VISITED ((GList *) element) = 1;
      place (element);
    }
    END_LOOP;
  }
  END_LOOP;

  /* Place up anything else */
  ELEMENT_LOOP (PCB->Data);
  {
    if (! visited[n])
    {
      place (element);
    }
  }
  END_LOOP;

  free (visited);

  IncrementUndoSerialNumber ();
  Redraw ();
  SetChangedFlag (1);

  return 0;
}
예제 #24
0
파일: crosshair.c 프로젝트: thequux/pcb
/* ---------------------------------------------------------------------------
 * draws all visible and attached objects of the pastebuffer
 */
static void
XORDrawBuffer (BufferTypePtr Buffer)
{
  Cardinal i;
  LocationType x, y;

  /* set offset */
  x = Crosshair.X - Buffer->X;
  y = Crosshair.Y - Buffer->Y;

  /* draw all visible layers */
  for (i = 0; i < max_copper_layer + 2; i++)
    if (PCB->Data->Layer[i].On)
      {
	LayerTypePtr layer = &Buffer->Data->Layer[i];

	LINE_LOOP (layer);
	{
/*
				XORDrawAttachedLine(x +line->Point1.X,
					y +line->Point1.Y, x +line->Point2.X,
					y +line->Point2.Y, line->Thickness);
*/
	  gui->draw_line (Crosshair.GC,
			  x + line->Point1.X, y + line->Point1.Y,
			  x + line->Point2.X, y + line->Point2.Y);
	}
	END_LOOP;
	ARC_LOOP (layer);
	{
	  gui->draw_arc (Crosshair.GC,
			 x + arc->X,
			 y + arc->Y,
			 arc->Width,
			 arc->Height, arc->StartAngle, arc->Delta);
	}
	END_LOOP;
	TEXT_LOOP (layer);
	{
	  BoxTypePtr box = &text->BoundingBox;
	  gui->draw_rect (Crosshair.GC,
			  x + box->X1, y + box->Y1, x + box->X2, y + box->Y2);
	}
	END_LOOP;
	/* the tmp polygon has n+1 points because the first
	 * and the last one are set to the same coordinates
	 */
	POLYGON_LOOP (layer);
	{
	  XORPolygon (polygon, x, y);
	}
	END_LOOP;
      }

  /* draw elements if visible */
  if (PCB->PinOn && PCB->ElementOn)
    ELEMENT_LOOP (Buffer->Data);
  {
    if (FRONT (element) || PCB->InvisibleObjectsOn)
      XORDrawElement (element, x, y);
  }
  END_LOOP;

  /* and the vias, move offset by thickness/2 */
  if (PCB->ViaOn)
    VIA_LOOP (Buffer->Data);
  {
    gui->draw_arc (Crosshair.GC,
		   x + via->X, y + via->Y,
		   via->Thickness / 2, via->Thickness / 2, 0, 360);
  }
  END_LOOP;
}
예제 #25
0
파일: autoplace.c 프로젝트: bert/pcb-update
/* ---------------------------------------------------------------------------
 * 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);
}
예제 #26
0
파일: report.c 프로젝트: 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;
}
예제 #27
0
파일: report.c 프로젝트: 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;
}
예제 #28
0
파일: mymem.c 프로젝트: bgamari/geda-pcb
/* ---------------------------------------------------------------------------
 * free memory used by data struct
 */
void
FreeDataMemory (DataType *data)
{
  LayerType *layer;
  int i;

  if (data == NULL)
    return;

  VIA_LOOP (data);
  {
    free (via->Name);
  }
  END_LOOP;
  g_list_free_full (data->Via, (GDestroyNotify)FreeVia);
  ELEMENT_LOOP (data);
  {
    FreeElementMemory (element);
  }
  END_LOOP;
  g_list_free_full (data->Element, (GDestroyNotify)FreeElement);
  g_list_free_full (data->Rat, (GDestroyNotify)FreeRat);

  for (layer = data->Layer, i = 0; i < MAX_LAYER + 2; layer++, i++)
    {
      FreeAttributeListMemory (&layer->Attributes);
      TEXT_LOOP (layer);
      {
        free (text->TextString);
      }
      END_LOOP;
      if (layer->Name)
        free (layer->Name);
      LINE_LOOP (layer);
      {
        if (line->Number)
          free (line->Number);
      }
      END_LOOP;
      g_list_free_full (layer->Line, (GDestroyNotify)FreeLine);
      g_list_free_full (layer->Arc, (GDestroyNotify)FreeArc);
      g_list_free_full (layer->Text, (GDestroyNotify)FreeText);
      POLYGON_LOOP (layer);
      {
        FreePolygonMemory (polygon);
      }
      END_LOOP;
      g_list_free_full (layer->Polygon, (GDestroyNotify)FreePolygon);
      if (layer->line_tree)
        r_destroy_tree (&layer->line_tree);
      if (layer->arc_tree)
        r_destroy_tree (&layer->arc_tree);
      if (layer->text_tree)
        r_destroy_tree (&layer->text_tree);
      if (layer->polygon_tree)
        r_destroy_tree (&layer->polygon_tree);
    }

  if (data->element_tree)
    r_destroy_tree (&data->element_tree);
  for (i = 0; i < MAX_ELEMENTNAMES; i++)
    if (data->name_tree[i])
      r_destroy_tree (&data->name_tree[i]);
  if (data->via_tree)
    r_destroy_tree (&data->via_tree);
  if (data->pin_tree)
    r_destroy_tree (&data->pin_tree);
  if (data->pad_tree)
    r_destroy_tree (&data->pad_tree);
  if (data->rat_tree)
    r_destroy_tree (&data->rat_tree);
  /* clear struct */
  memset (data, 0, sizeof (DataType));
}
예제 #29
0
/*
 * AlignText(X, [Lefts/Rights/Centers, [First/Last/Crosshair/Average[, Gridless]]])
 * AlignText(Y, [Tops/Bottoms/Centers, [First/Last/Crosshair/Average[, Gridless]]])
 *
 *	X or Y		- Select which axis will move, other is untouched
 *	Lefts, Rights,
 *	Tops, Bottoms,
 *	Centers         - Pick alignment point within each element.
 *	                  NB: text objects have no Mark
 *	First, Last, 
 *	Crosshair, 
 *	Average		- Alignment reference, First=Topmost/Leftmost,
 *			  Last=Bottommost/Rightmost, Average or Crosshair point
 *	Gridless	- Do not force results to align to prevailing grid
 *
 * Defaults are Lefts/Tops, First
 */
static int
aligntext(int argc, char **argv, Coord x, Coord y)
{
	int dir;
	int point;
	int reference;
	int gridless;
	Coord q;
	Coord p, dp, dx, dy;
	int changed = 0;

	if (argc < 1 || argc > 4) {
		AFAIL(aligntext);
	}

	/* parse direction arg */
	switch ((dir = keyword(ARG(0)))) {
	case K_X:
	case K_Y:
		break;
	default:
		AFAIL(aligntext);
	}

	/* parse point (within each element) which will be aligned */
	switch ((point = keyword(ARG(1)))) {
	case K_Centers:
		break;
	case K_Lefts:
	case K_Rights:
		if (dir == K_Y) {
			AFAIL(aligntext);
		}
		break;
	case K_Tops:
	case K_Bottoms:
		if (dir == K_X) {
			AFAIL(aligntext);
		}
		break;
	case K_none:
		/* default value */
		if (dir == K_X) {
			point = K_Lefts;
		} else {
			point = K_Tops;
		}
		break;
	default:
		AFAIL(aligntext);
	}

	/* parse reference which will determine alignment coordinates */
	switch ((reference = keyword(ARG(2)))) {
	case K_First:
	case K_Last:
	case K_Average:
	case K_Crosshair:
		break;
	case K_none:
		reference = K_First;	/* default value */
		break;
	default:
		AFAIL(aligntext);
	}

	/* optionally work off the grid (solar cells!) */
	switch (keyword(ARG(3))) {
	case K_Gridless:
		gridless = 1;
		break;
	case K_none:
		gridless = 0;
		break;
	default:
		AFAIL(aligntext);
	}

	SaveUndoSerialNumber();

	/* find the final alignment coordinate using the above options */
	q = reference_coord(K_aligntext, Crosshair.X, Crosshair.Y,
				dir, point, reference);

	/* move all selected elements to the new coordinate */

	/* selected text part of an element */
	ELEMENT_LOOP(PCB->Data);
	{
		TextType *text;
		text = &(element)->Name[NAME_INDEX(PCB)];
		if (! TEST_FLAG (SELECTEDFLAG, text))
			continue;
		/* find delta from reference point to reference point */
		p = coord(text, dir, point);
		dp = q - p;
		/* ...but if we're gridful, keep the mark on the grid */
		/* TODO re-enable for text, need textcoord()
		if (! gridless) {
			dp -= (coord(text, dir, K_Marks) + dp)
					% (long) (PCB->Grid);
		}
		*/
		if (dp) {
			/* move from generic to X or Y */
			dx = dy = dp;
			if (dir == K_X)
				dy = 0;
			else
				dx = 0;
			MoveObject(ELEMENTNAME_TYPE, element, text, text, dx, dy);
			changed = 1;
		}
	}
	END_LOOP;

	/* Selected bare text objects */
	ALLTEXT_LOOP (PCB->Data);
	{
	  if (TEST_FLAG (SELECTEDFLAG, text))
	    {
		/* find delta from reference point to reference point */
		p = coord(text, dir, point);
		dp = q - p;
		/* ...but if we're gridful, keep the mark on the grid */
		/* TODO re-enable for text, need textcoord()
		if (! gridless) {
			dp -= (coord(text, dir, K_Marks) + dp)
					% (long) (PCB->Grid);
		}
		*/
		if (dp) {
			/* move from generic to X or Y */
			dx = dy = dp;
			if (dir == K_X)
				dy = 0;
			else
				dx = 0;
			MoveObject(TEXT_TYPE, layer, text, text, dx, dy);
			changed = 1;
		}
	    }
	}
	ENDALL_LOOP;

	if (changed) {
		RestoreUndoSerialNumber();
		IncrementUndoSerialNumber();
		Redraw();
		SetChangedFlag(true);
	}

	free_texts_by_pos();

	return 0;
}
예제 #30
0
파일: copy.c 프로젝트: bgamari/geda-pcb
/* ---------------------------------------------------------------------------
 * pastes the contents of the buffer to the layout. Only visible objects
 * are handled by the routine.
 */
bool
CopyPastebufferToLayout (Coord X, Coord Y)
{
  Cardinal i;
  bool changed = false;

#ifdef DEBUG
  printf("Entering CopyPastebufferToLayout.....\n");
#endif

  /* set movement vector */
  DeltaX = X - PASTEBUFFER->X, DeltaY = Y - PASTEBUFFER->Y;

  /* paste all layers */
  for (i = 0; i < max_copper_layer + 2; i++)
    {
      LayerType *sourcelayer = &PASTEBUFFER->Data->Layer[i];
      LayerType *destlayer = LAYER_PTR (i);

      if (destlayer->On)
	{
	  changed = changed ||
	    (sourcelayer->LineN != 0) ||
	    (sourcelayer->ArcN != 0) ||
	    (sourcelayer->PolygonN != 0) || (sourcelayer->TextN != 0);
	  LINE_LOOP (sourcelayer);
	  {
	    CopyLine (destlayer, line);
	  }
	  END_LOOP;
	  ARC_LOOP (sourcelayer);
	  {
	    CopyArc (destlayer, arc);
	  }
	  END_LOOP;
	  TEXT_LOOP (sourcelayer);
	  {
	    CopyText (destlayer, text);
	  }
	  END_LOOP;
	  POLYGON_LOOP (sourcelayer);
	  {
	    CopyPolygon (destlayer, polygon);
	  }
	  END_LOOP;
	}
    }

  /* paste elements */
  if (PCB->PinOn && PCB->ElementOn)
    {
      ELEMENT_LOOP (PASTEBUFFER->Data);
      {
#ifdef DEBUG
	printf("In CopyPastebufferToLayout, pasting element %s\n",
	      element->Name[1].TextString);
#endif
	if (FRONT (element) || PCB->InvisibleObjectsOn)
	  {
	    CopyElement (element);
	    changed = true;
	  }
      }
      END_LOOP;
    }

  /* finally the vias */
  if (PCB->ViaOn)
    {
      changed |= (PASTEBUFFER->Data->ViaN != 0);
      VIA_LOOP (PASTEBUFFER->Data);
      {
	CopyVia (via);
      }
      END_LOOP;
    }

  if (changed)
    {
      Draw ();
      IncrementUndoSerialNumber ();
    }

#ifdef DEBUG
  printf("  .... Leaving CopyPastebufferToLayout.\n");
#endif

  return (changed);
}