Exemplo n.º 1
0
static int
CommandSaveLayout (int argc, char **argv, Coord x, Coord y)
{
  switch (argc)
    {
    case 0:
      if (PCB->Filename)
        {
          if (SavePCB (PCB->Filename) == 0)
            SetChangedFlag (false);
        }
      else
	Message ("No filename to save to yet\n");
      break;

    case 1:
      if (SavePCB (argv[0]) == 0)
        {
          SetChangedFlag (false);
          free (PCB->Filename);
          PCB->Filename = strdup (argv[0]);
           if (gui->notify_filename_changed != NULL)
            gui->notify_filename_changed ();
        }
      break;

    default:
      Message ("Usage: s [name] | w [name]\n  saves layout data\n");
      return (1);
    }
  return (0);
}
Exemplo n.º 2
0
static void
selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
{
    GtkTreeModel *model;
    GtkTreeIter iter;
    GhidDrcViolation *violation;
    int i;

    if (!gtk_tree_selection_get_selected (selection, &model, &iter))
    {
        if (ClearFlagOnAllObjects (true, FOUNDFLAG))
        {
            IncrementUndoSerialNumber ();
            Draw ();
        }
        return;
    }

    /* Check the selected node has children, if so; return. */
    if (gtk_tree_model_iter_has_child (model, &iter))
        return;

    gtk_tree_model_get (model, &iter, DRC_VIOLATION_OBJ_COL, &violation, -1);

    ClearFlagOnAllObjects (true, FOUNDFLAG);

    if (violation == NULL)
        return;

    /* Flag the objects listed against this DRC violation */
    for (i = 0; i < violation->object_count; i++)
    {
        int object_id = violation->object_id_list[i];
        int object_type = violation->object_type_list[i];
        int found_type;
        void *ptr1, *ptr2, *ptr3;

        found_type = SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3,
                                       object_id, object_type);
        if (found_type == NO_TYPE)
        {
            Message (_("Object ID %i identified during DRC was not found. Stale DRC window?\n"),
                     object_id);
            continue;
        }
        AddObjectToFlagUndoList (object_type, ptr1, ptr2, ptr3);
        SET_FLAG (FOUNDFLAG, (AnyObjectType *)ptr2);
        switch (violation->object_type_list[i])
        {
        case LINE_TYPE:
        case ARC_TYPE:
        case POLYGON_TYPE:
            ChangeGroupVisibility (GetLayerNumber (PCB->Data, (LayerType *) ptr1), true, true);
        }
        DrawObject (object_type, ptr1, ptr2);
    }
    SetChangedFlag (true);
    IncrementUndoSerialNumber ();
    Draw();
}
Exemplo n.º 3
0
static int
autocrop (int argc, char **argv, Coord x, Coord y)
{
//  int changed = 0;
  Coord dx, dy, pad;
  BoxType *box;

  box = GetDataBoundingBox (PCB->Data); /* handy! */
  if (!box || (box->X1 == box->X2 || box->Y1 == box->Y2))
  {
    /* board would become degenerate */
    return 0;
  }
  /*
   * Now X1/Y1 are the distance to move the left/top edge
   * (actually moving all components to the left/up) such that
   * the exact edge of the leftmost/topmost component would touch
   * the edge.  Reduce the move by the edge relief requirement XXX
   * and expand the board by the same amount.
   */
  pad = PCB->minWid * 5; /* XXX real edge clearance */
  dx = -box->X1 + pad;
  dy = -box->Y1 + pad;
  box->X2 += pad;
  box->Y2 += pad;
  /*
   * Round move to keep components grid-aligned, then translate the
   * upper coordinates into the new space.
   */
  dx -= dx % (long) PCB->Grid;
  dy -= dy % (long) PCB->Grid;
  box->X2 += dx;
  box->Y2 += dy;
  /*
   * Avoid touching any data if there's nothing to do.
   */
  if (dx == 0 && dy == 0 && PCB->MaxWidth == box->X2
    && PCB->MaxHeight == box->Y2)
  {
    return 0;
  }
  /* Resize -- XXX cannot be undone */
  PCB->MaxWidth = box->X2;
  PCB->MaxHeight = box->Y2;
  MoveAll (dx, dy);
  IncrementUndoSerialNumber ();
  Redraw ();
  SetChangedFlag (1);
  return 0;
}
Exemplo n.º 4
0
Arquivo: insert.c Projeto: thequux/pcb
/* ---------------------------------------------------------------------------
 * inserts a point into a polygon
 */
static void *
InsertPointIntoPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
{
  PointType save;
  Cardinal n;
  LineType line;

  if (!Forcible)
    {
      /*
       * first make sure adding the point is sensible
       */
      line.Thickness = 0;
      line.Point1 = Polygon->Points[prev_contour_point (Polygon, InsertAt)];
      line.Point2 = Polygon->Points[InsertAt];
      if (IsPointOnLine ((float) InsertX, (float) InsertY, 0.0, &line))
	return (NULL);
    }
  /*
   * second, shift the points up to make room for the new point
   */
  ErasePolygon (Polygon);
  r_delete_entry (Layer->polygon_tree, (BoxTypePtr) Polygon);
  save = *CreateNewPointInPolygon (Polygon, InsertX, InsertY);
  for (n = Polygon->PointN - 1; n > InsertAt; n--)
    Polygon->Points[n] = Polygon->Points[n - 1];

  /* Shift up indices of any holes */
  for (n = 0; n < Polygon->HoleIndexN; n++)
    if (Polygon->HoleIndex[n] > InsertAt ||
	(InsertLast && Polygon->HoleIndex[n] == InsertAt))
      Polygon->HoleIndex[n]++;

  Polygon->Points[InsertAt] = save;
  SetChangedFlag (true);
  AddObjectToInsertPointUndoList (POLYGONPOINT_TYPE, Layer, Polygon,
				  &Polygon->Points[InsertAt]);

  SetPolygonBoundingBox (Polygon);
  r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
  InitClip (PCB->Data, Layer, Polygon);
  if (Forcible || !RemoveExcessPolygonPoints (Layer, Polygon))
    {
      DrawPolygon (Layer, Polygon, 0);
      Draw ();
    }
  return (&Polygon->Points[InsertAt]);
}
Exemplo n.º 5
0
Arquivo: file.c Projeto: thequux/pcb
/* ---------------------------------------------------------------------------
 * save PCB
 */
int
SavePCB (char *Filename)
{
  int retcode;
  char *copy;

  if (!(retcode = WritePipe (Filename, true)))
    {
      /* thanks to Nick Bailey for the bug-fix;
       * first of all make a copy of the passed filename because
       * it might be identical to 'PCB->Filename'
       */
      copy = strdup (Filename);
      free (PCB->Filename);
      PCB->Filename = copy;
      SetChangedFlag (false);
    }
  return (retcode);
}
Exemplo n.º 6
0
/* %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;
}
Exemplo n.º 7
0
/* ---------------------------------------------------------------------------
 * load PCB
 * parse the file with enabled 'PCB mode' (see parser)
 * if successful, update some other stuff
 *
 * If revert is true, we pass "revert" as a parameter
 * to the HID's PCBChanged action.
 */
static int
real_load_pcb (char *Filename, bool revert)
{
  const char *unit_suffix, *grid_size;
  char *new_filename;
  PCBType *newPCB = CreateNewPCB (false);
  PCBType *oldPCB;
#ifdef DEBUG
  double elapsed;
  clock_t start, end;

  start = clock ();
#endif

  new_filename = strdup (Filename);

  oldPCB = PCB;
  PCB = newPCB;

  /* mark the default font invalid to know if the file has one */
  newPCB->Font.Valid = false;

  /* new data isn't added to the undo list */
  if (!ParsePCB (PCB, new_filename))
    {
      RemovePCB (oldPCB);

      CreateNewPCBPost (PCB, 0);
      ResetStackAndVisibility ();

      /* update cursor location */
      Crosshair.X = CLAMP (PCB->CursorX, 0, PCB->MaxWidth);
      Crosshair.Y = CLAMP (PCB->CursorY, 0, PCB->MaxHeight);

      /* update cursor confinement and output area (scrollbars) */
      ChangePCBSize (PCB->MaxWidth, PCB->MaxHeight);

      /* enable default font if necessary */
      if (!PCB->Font.Valid)
	{
	  Message (_
		   ("File '%s' has no font information, using default font\n"),
		   new_filename);
	  PCB->Font.Valid = true;
	}

      /* clear 'changed flag' */
      SetChangedFlag (false);
      PCB->Filename = new_filename;
      /* just in case a bad file saved file is loaded */

      /* Use attribute PCB::grid::unit as unit, if we can */
      unit_suffix = AttributeGet (PCB, "PCB::grid::unit");
      if (unit_suffix && *unit_suffix)
        {
          const Unit *new_unit = get_unit_struct (unit_suffix);
          if (new_unit)
            Settings.grid_unit = new_unit;
        }
      AttributePut (PCB, "PCB::grid::unit", Settings.grid_unit->suffix);
      /* Use attribute PCB::grid::size as size, if we can */
      grid_size = AttributeGet (PCB, "PCB::grid::size");
      if (grid_size)
        {
          PCB->Grid = GetValue (grid_size, NULL, NULL);
        }
 
      sort_netlist ();

      set_some_route_style ();

      if (revert)
        hid_actionl ("PCBChanged", "revert", NULL);
      else
        hid_action ("PCBChanged");

#ifdef DEBUG
      end = clock ();
      elapsed = ((double) (end - start)) / CLOCKS_PER_SEC;
      gui->log ("Loading file %s took %f seconds of CPU time\n",
		new_filename, elapsed);
#endif

      return (0);
    }
  PCB = oldPCB;
  hid_action ("PCBChanged");

  /* release unused memory */
  RemovePCB (newPCB);
  return (1);
}
Exemplo n.º 8
0
/*
 * DistributeText(X, [Lefts/Rights/Centers/Gaps, [First/Last/Crosshair, First/Last/Crosshair[, Gridless]]])
 * DistributeText(Y, [Tops/Bottoms/Centers/Gaps, [First/Last/Crosshair, First/Last/Crosshair[, Gridless]]])
 *
 * As with align, plus:
 *
 *	Gaps		- Make gaps even rather than spreading points evenly
 *	First, Last,
 *	Crosshair	- Two arguments specifying both ends of the
 *			  distribution, they can't both be the same.
 *
 * Defaults are Lefts/Tops, First, Last
 *
 * Distributed texts always retain the same relative order they had
 * before they were distributed.
 */
static int
distributetext(int argc, char **argv, Coord x, Coord y)
{
	int dir;
	int point;
	int refa, refb;
	int gridless;
	Coord s, e, slack;
	int divisor;
	int changed = 0;
	int i;

	if (argc < 1 || argc == 3 || argc > 4) {
		AFAIL(distributetext);
	}

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

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

	/* parse reference which will determine first distribution coordinate */
	switch ((refa = keyword(ARG(2)))) {
	case K_First:
	case K_Last:
	case K_Average:
	case K_Crosshair:
		break;
	case K_none:
		refa = K_First;	/* default value */
		break;
	default:
		AFAIL(distributetext);
	}

	/* parse reference which will determine final distribution coordinate */
	switch ((refb = keyword(ARG(3)))) {
	case K_First:
	case K_Last:
	case K_Average:
	case K_Crosshair:
		break;
	case K_none:
		refb = K_Last;	/* default value */
		break;
	default:
		AFAIL(distributetext);
	}
	if (refa == refb) {
		AFAIL(distributetext);
	}

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

	SaveUndoSerialNumber();

	/* build list of texts in orthogonal axis order */
	sort_texts_by_pos(K_distributetext, dir, point);

	/* find the endpoints given the above options */
	s = reference_coord(K_distributetext, x, y, dir, point, refa);
	e = reference_coord(K_distributetext, x, y, dir, point, refb);
	slack = e - s;

	/* use this divisor to calculate spacing (for 1 elt, avoid 1/0) */
	divisor = (ntexts_by_pos > 1) ? (ntexts_by_pos - 1) : 1;

	/* even the gaps instead of the edges or whatnot */
	/* find the "slack" in the row */
	if (point == K_Gaps) {
		Coord w;

		/* subtract all the "widths" from the slack */
		for (i = 0; i < ntexts_by_pos; ++i) {
			TextType *text = texts_by_pos[i].text;

			/* coord doesn't care if I mix Lefts/Tops */
			w = texts_by_pos[i].width =
				coord(text, dir, K_Rights) -
				coord(text, dir, K_Lefts);
			/* Gaps distribution is on centers, so half of
			 * first and last text don't count */
			if (i == 0 || i == ntexts_by_pos - 1) {
				w /= 2;
			}
			slack -= w;
		}
		/* slack could be negative */
	}

	/* move all selected texts to the new coordinate */
	for (i = 0; i < ntexts_by_pos; ++i) {
		TextType *text = texts_by_pos[i].text;
		int type = texts_by_pos[i].type;
		Coord p, q, dp, dx, dy;

		/* find reference point for this text */
		q = s + slack * i / divisor;
		/* 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 grid
		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;
			/* need to know if the text is part of an element,
			 * all are TEXT_TYPE, but text associated with an
			 * element is also ELEMENTNAME_TYPE.  For undo, this is
			 * significant in search.c: SearchObjectByID.
			 *
			 * MoveObject() is better as in aligntext(), but we
			 * didn't keep the element reference when sorting.
			 * */
			MOVE_TEXT_LOWLEVEL(text, dx, dy);
			AddObjectToMoveUndoList(type, NULL, NULL,
						text, dx, dy);
			changed = 1;
		}
		/* in gaps mode, accumulate part widths */
		if (point == K_Gaps) {
			/* move remaining half of our text */
			s += texts_by_pos[i].width / 2;
			/* move half of next text */
			if (i < ntexts_by_pos - 1)
				s += texts_by_pos[i + 1].width / 2;
		}
	}

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

	free_texts_by_pos();

	return 0;
}
Exemplo n.º 9
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;
}
Exemplo n.º 10
0
Arquivo: file.c Projeto: thequux/pcb
/* ---------------------------------------------------------------------------
 * load PCB
 * parse the file with enabled 'PCB mode' (see parser)
 * if successful, update some other stuff
 */
int
LoadPCB (char *Filename)
{
  PCBTypePtr newPCB = CreateNewPCB (false);
  PCBTypePtr oldPCB;
  bool units_mm;
#ifdef DEBUG
  double elapsed;
  clock_t start, end;

  start = clock ();
#endif

  oldPCB = PCB;
  PCB = newPCB;

  /* new data isn't added to the undo list */
  if (!ParsePCB (PCB, Filename))
    {
      RemovePCB (oldPCB);

      CreateNewPCBPost (PCB, 0);
      ResetStackAndVisibility ();

      /* update cursor location */
      Crosshair.X = MAX (0, MIN (PCB->CursorX, (LocationType) PCB->MaxWidth));
      Crosshair.Y =
	MAX (0, MIN (PCB->CursorY, (LocationType) PCB->MaxHeight));

      Xorig = Crosshair.X - TO_PCB (Output.Width / 2);
      Yorig = Crosshair.Y - TO_PCB (Output.Height / 2);

      /* update cursor confinement and output area (scrollbars) */
      ChangePCBSize (PCB->MaxWidth, PCB->MaxHeight);

      /* create default font if necessary */
      if (!PCB->Font.Valid)
	{
	  Message (_
		   ("File '%s' has no font information, using default font\n"),
		   Filename);
	  CreateDefaultFont ();
	}

      /* clear 'changed flag' */
      SetChangedFlag (false);
      PCB->Filename = strdup (Filename);
      /* just in case a bad file saved file is loaded */

      units_mm = (PCB->Grid != (int) PCB->Grid) ? true : false;

      Settings.grid_units_mm = units_mm;

      sort_netlist ();

      set_some_route_style ();

      hid_action ("PCBChanged");

#ifdef DEBUG
      end = clock ();
      elapsed = ((double) (end - start)) / CLOCKS_PER_SEC;
      gui->log ("Loading file %s took %f seconds of CPU time\n",
		Filename, elapsed);
#endif

      return (0);
    }
  PCB = oldPCB;
  hid_action ("PCBChanged");

  /* release unused memory */
  RemovePCB (newPCB);
  return (1);
}
Exemplo n.º 11
0
static void
apply_vendor_map (void)
{
  int i;
  int changed, tot;
  bool state;

  state = vendorMapEnable;

  /* enable mapping */
  vendorMapEnable = true;

  /* reset our counts */
  changed = 0;
  tot = 0;

  /* If we have loaded vendor drills, then apply them to the design */
  if (n_vendor_drills > 0)
    {

      /* first all the vias */
      VIA_LOOP (PCB->Data);
      {
	tot++;
	if (via->DrillingHole != vendorDrillMap (via->DrillingHole))
	  {
	    /* only change unlocked vias */
	    if (!TEST_FLAG (LOCKFLAG, via))
	      {
		if (ChangeObject2ndSize (VIA_TYPE, via, NULL, NULL,
					 vendorDrillMap (via->DrillingHole),
					 true, false))
		  changed++;
		else
		  {
		    Message (_
			     ("Via at %.2f, %.2f not changed.  Possible reasons:\n"
			      "\t- pad size too small\n"
			      "\t- new size would be too large or too small\n"),
			     0.01 * via->X, 0.01 * via->Y);
		  }
	      }
	    else
	      {
		Message (_("Locked via at %.2f, %.2f not changed.\n"),
			 0.01 * via->X, 0.01 * via->Y);
	      }
	  }
      }
      END_LOOP;

      /* and now the pins */
      ELEMENT_LOOP (PCB->Data);
      {
	/*
	 * first figure out if this element should be skipped for some
	 * reason
	 */
	if (vendorIsElementMappable (element))
	  {
	    /* the element is ok to modify, so iterate over its pins */
	    PIN_LOOP (element);
	    {
	      tot++;
	      if (pin->DrillingHole != vendorDrillMap (pin->DrillingHole))
		{
		  if (!TEST_FLAG (LOCKFLAG, pin))
		    {
		      if (ChangeObject2ndSize (PIN_TYPE, element, pin, NULL,
					       vendorDrillMap (pin->
							       DrillingHole),
					       true, false))
			changed++;
		      else
			{
			  Message (_
				   ("Pin %s (%s) at %.2f, %.2f (element %s, %s, %s) not changed.\n"
				    "\tPossible reasons:\n"
				    "\t- pad size too small\n"
				    "\t- new size would be too large or too small\n"),
				   UNKNOWN (pin->Number), UNKNOWN (pin->Name),
				   0.01 * pin->X, 0.01 * pin->Y,
				   UNKNOWN (NAMEONPCB_NAME (element)),
				   UNKNOWN (VALUE_NAME (element)),
				   UNKNOWN (DESCRIPTION_NAME (element)));
			}
		    }
		  else
		    {
		      Message (_
			       ("Locked pin at %-6.2f, %-6.2f not changed.\n"),
			       0.01 * pin->X, 0.01 * pin->Y);
		    }
		}
	    }
	    END_LOOP;
	  }
      }
      END_LOOP;

      Message (_("Updated %d drill sizes out of %d total\n"), changed, tot);

      /* Update the current Via */
      if (Settings.ViaDrillingHole !=
	  vendorDrillMap (Settings.ViaDrillingHole))
	{
	  changed++;
	  Settings.ViaDrillingHole =
	    vendorDrillMap (Settings.ViaDrillingHole);
	  Message (_("Adjusted active via hole size to be %6.2f mils\n"),
		   0.01 * Settings.ViaDrillingHole);
	}

      /* and update the vias for the various routing styles */
      for (i = 0; i < NUM_STYLES; i++)
	{
	  if (PCB->RouteStyle[i].Hole !=
	      vendorDrillMap (PCB->RouteStyle[i].Hole))
	    {
	      changed++;
	      PCB->RouteStyle[i].Hole =
		vendorDrillMap (PCB->RouteStyle[i].Hole);
	      Message (_
		       ("Adjusted %s routing style via hole size to be %6.2f mils\n"),
		       PCB->RouteStyle[i].Name,
		       0.01 * PCB->RouteStyle[i].Hole);
	      if (PCB->RouteStyle[i].Diameter <
		  PCB->RouteStyle[i].Hole + MIN_PINORVIACOPPER)
		{
		  PCB->RouteStyle[i].Diameter =
		    PCB->RouteStyle[i].Hole + MIN_PINORVIACOPPER;
		  Message (_
			   ("Increased %s routing style via diameter to %6.2f mils\n"),
			   PCB->RouteStyle[i].Name,
			   0.01 * PCB->RouteStyle[i].Diameter);
		}
	    }
	}

      /* 
       * if we've changed anything, indicate that we need to save the
       * file, redraw things, and make sure we can undo.
       */
      if (changed)
	{
	  SetChangedFlag (true);
	  Redraw ();
	  IncrementUndoSerialNumber ();
	}
    }

  /* restore mapping on/off */
  vendorMapEnable = state;
}
Exemplo n.º 12
0
/*
 * Distribute(X, [Lefts/Rights/Centers/Marks/Gaps, [First/Last/Crosshair, First/Last/Crosshair[, Gridless]]])
 * Distribute(Y, [Tops/Bottoms/Centers/Marks/Gaps, [First/Last/Crosshair, First/Last/Crosshair[, Gridless]]])
 *
 * As with align, plus:
 *
 *	Gaps		- Make gaps even rather than spreading points evenly
 *	First, Last,
 *	Crosshair	- Two arguments specifying both ends of the
 *			  distribution, they can't both be the same.
 *
 * Defaults are Marks, First, Last
 *
 * Distributed elements always retain the same relative order they had
 * before they were distributed.
 */
static int
distribute(int argc, char **argv, Coord x, Coord y)
{
	int dir;
	int point;
	int refa, refb;
	int gridless;
	Coord s, e, slack;
	int divisor;
	int changed = 0;
	int i;

	if (argc < 1 || argc == 3 || argc > 4) {
		AFAIL(distribute);
	}

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

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

	/* parse reference which will determine first distribution coordinate */
	switch ((refa = keyword(ARG(2)))) {
	case K_First:
	case K_Last:
	case K_Average:
	case K_Crosshair:
		break;
	case K_none:
		refa = K_First;	/* default value */
		break;
	default:
		AFAIL(distribute);
	}

	/* parse reference which will determine final distribution coordinate */
	switch ((refb = keyword(ARG(3)))) {
	case K_First:
	case K_Last:
	case K_Average:
	case K_Crosshair:
		break;
	case K_none:
		refb = K_Last;	/* default value */
		break;
	default:
		AFAIL(distribute);
	}
	if (refa == refb) {
		AFAIL(distribute);
	}

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

	/* build list of elements in orthogonal axis order */
	sort_elements_by_pos(K_distribute, dir, point);

	/* find the endpoints given the above options */
	s = reference_coord(K_distribute, x, y, dir, point, refa);
	e = reference_coord(K_distribute, x, y, dir, point, refb);
	slack = e - s;

	/* use this divisor to calculate spacing (for 1 elt, avoid 1/0) */
	divisor = (nelements_by_pos > 1) ? (nelements_by_pos - 1) : 1;

	/* even the gaps instead of the edges or whatnot */
	/* find the "slack" in the row */
	if (point == K_Gaps) {
		Coord w;

		/* subtract all the "widths" from the slack */
		for (i = 0; i < nelements_by_pos; ++i) {
			ElementType *element = elements_by_pos[i].element;

			/* coord doesn't care if I mix Lefts/Tops */
			w = elements_by_pos[i].width =
				coord(element, dir, K_Rights) -
				coord(element, dir, K_Lefts);
			/* Gaps distribution is on centers, so half of
			 * first and last element don't count */
			if (i == 0 || i == nelements_by_pos - 1) {
				w /= 2;
			}
			slack -= w;
		}
		/* slack could be negative */
	}

	/* move all selected elements to the new coordinate */
	for (i = 0; i < nelements_by_pos; ++i) {
		ElementType *element = elements_by_pos[i].element;
		Coord p, q, dp, dx, dy;

		/* find reference point for this element */
		q = s + slack * i / divisor;
		/* find delta from reference point to reference point */
		p = coord(element, dir, point);
		dp = q - p;
		/* ...but if we're gridful, keep the mark on the grid */
		if (! gridless) {
			dp -= (coord(element, 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;
			MoveElementLowLevel(PCB->Data, element, dx, dy);
			AddObjectToMoveUndoList(ELEMENT_TYPE, NULL, NULL,
						element, dx, dy);
			changed = 1;
		}
		/* in gaps mode, accumulate part widths */
		if (point == K_Gaps) {
			/* move remaining half of our element */
			s += elements_by_pos[i].width / 2;
			/* move half of next element */
			if (i < nelements_by_pos - 1)
				s += elements_by_pos[i + 1].width / 2;
		}
	}

	if (changed) {
		IncrementUndoSerialNumber();
		Redraw();
		SetChangedFlag(1);
	}

	free_elements_by_pos();

	return 0;
}
Exemplo n.º 13
0
/*
 * Align(X, [Lefts/Rights/Centers/Marks, [First/Last/Crosshair/Average[, Gridless]]])
 * Align(Y, [Tops/Bottoms/Centers/Marks, [First/Last/Crosshair/Average[, Gridless]]])
 *
 *	X or Y		- Select which axis will move, other is untouched
 *	Lefts, Rights,
 *	Tops, Bottoms,
 *	Centers, Marks	- Pick alignment point within each element
 *	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 Marks, First
 */
static int
align(int argc, char **argv, Coord x, Coord y)
{
	int dir;
	int point;
	int reference;
	int gridless;
	Coord q;
	int changed = 0;

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

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

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

	/* 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(align);
	}

	/* 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(align);
	}

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

	/* move all selected elements to the new coordinate */
	ELEMENT_LOOP(PCB->Data);
	{
		Coord p, dp, dx, dy;

		if (! TEST_FLAG (SELECTEDFLAG, element))
			continue;
		/* find delta from reference point to reference point */
		p = coord(element, dir, point);
		dp = q - p;
		/* ...but if we're gridful, keep the mark on the grid */
		if (! gridless) {
			dp -= (coord(element, 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;
			MoveElementLowLevel(PCB->Data, element, dx, dy);
			AddObjectToMoveUndoList(ELEMENT_TYPE, NULL, NULL,
						element, dx, dy);
			changed = 1;
		}
	}
	END_LOOP;

	if (changed) {
		IncrementUndoSerialNumber();
		Redraw();
		SetChangedFlag(1);
	}

	free_elements_by_pos();

	return 0;
}