/* ---------------------------------------------------------------------- * post-process settings. */ static void settings_post_process () { char *tmps; if (Settings.LineThickness > MAX_LINESIZE || Settings.LineThickness < MIN_LINESIZE) Settings.LineThickness = MIL_TO_COORD(10); if (Settings.ViaThickness > MAX_PINORVIASIZE || Settings.ViaThickness < MIN_PINORVIASIZE) Settings.ViaThickness = MIL_TO_COORD(40); if (Settings.ViaDrillingHole <= 0) Settings.ViaDrillingHole = DEFAULT_DRILLINGHOLE * Settings.ViaThickness / 100; Settings.MaxWidth = CLAMP (Settings.MaxWidth, MIN_SIZE, MAX_COORD); Settings.MaxHeight = CLAMP (Settings.MaxHeight, MIN_SIZE, MAX_COORD); if (Settings.Routes != NULL) ParseRouteString (Settings.Routes, &Settings.RouteStyle[0], "cmil"); /* * Make sure we have settings for some various programs we may wish * to call */ if (Settings.MakeProgram == NULL) { tmps = getenv ("PCB_MAKE_PROGRAM"); if (tmps != NULL) Settings.MakeProgram = strdup (tmps); } if (Settings.MakeProgram == NULL) { Settings.MakeProgram = strdup ("make"); } if (Settings.GnetlistProgram == NULL) { tmps = getenv ("PCB_GNETLIST"); if (tmps != NULL) Settings.GnetlistProgram = strdup (tmps); } if (Settings.GnetlistProgram == NULL) { Settings.GnetlistProgram = strdup ("gnetlist"); } if (grid_units) Settings.grid_unit = get_unit_struct (grid_units); if (!grid_units || Settings.grid_unit == NULL) Settings.grid_unit = get_unit_struct ("mil"); Settings.increments = get_increments_struct (Settings.grid_unit->suffix); }
/* --------------------------------------------------------------------------- * Auto-place selected components. */ bool AutoPlaceSelected (void) { NetListType *Nets; PointerListType Selected = { 0, 0, NULL }; PerturbationType pt; double C0, T0; bool changed = false; /* (initial netlist processing copied from AddAllRats) */ /* the netlist library has the text form * ProcNetlist fills in the Netlist * structure the way the final routing * is supposed to look */ Nets = ProcNetlist (&PCB->NetlistLib); if (!Nets) { Message (_("Can't add rat lines because no netlist is loaded.\n")); goto done; } Selected = collectSelectedElements (); if (Selected.PtrN == 0) { Message (_("No elements selected to autoplace.\n")); goto done; } /* simulated annealing */ { /* compute T0 by doing a random series of moves. */ const int TRIALS = 10; const double Tx = MIL_TO_COORD (300), P = 0.95; double Cs = 0.0; int i; C0 = ComputeCost (Nets, Tx, Tx); for (i = 0; i < TRIALS; i++) { pt = createPerturbation (&Selected, INCH_TO_COORD (1)); doPerturb (&pt, false); Cs += fabs (ComputeCost (Nets, Tx, Tx) - C0); doPerturb (&pt, true); } T0 = -(Cs / TRIALS) / log (P); printf ("Initial T: %f\n", T0); } /* now anneal in earnest */ { double T = T0; long steps = 0; int good_moves = 0, moves = 0; const int good_move_cutoff = CostParameter.m * Selected.PtrN; const int move_cutoff = 2 * good_move_cutoff; printf ("Starting cost is %.0f\n", ComputeCost (Nets, T0, 5)); C0 = ComputeCost (Nets, T0, T); while (1) { double Cprime; pt = createPerturbation (&Selected, T); doPerturb (&pt, false); Cprime = ComputeCost (Nets, T0, T); if (Cprime < C0) { /* good move! */ C0 = Cprime; good_moves++; steps++; } else if ((random () / (double) RAND_MAX) < exp (MIN (MAX (-20, (C0 - Cprime) / T), 20))) { /* not good but keep it anyway */ C0 = Cprime; steps++; } else doPerturb (&pt, true); /* undo last change */ moves++; /* are we at the end of a stage? */ if (good_moves >= good_move_cutoff || moves >= move_cutoff) { printf ("END OF STAGE: COST %.0f\t" "GOOD_MOVES %d\tMOVES %d\t" "T: %.1f\n", C0, good_moves, moves, T); /* is this the end? */ if (T < 5 || good_moves < moves / CostParameter.good_ratio) break; /* nope, adjust T and continue */ moves = good_moves = 0; T *= CostParameter.gamma; /* cost is T dependent, so recompute */ C0 = ComputeCost (Nets, T0, T); } } changed = (steps > 0); } done: if (changed) { DeleteRats (false); AddAllRats (false, NULL); Redraw (); } FreePointerListMemory (&Selected); return (changed); }
/* --------------------------------------------------------------------------- * Perturb: * 1) flip SMD from solder side to component side or vice-versa. * 2) rotate component 90, 180, or 270 degrees. * 3) shift component random + or - amount in random direction. * (magnitude of shift decreases over time) * -- Only perturb selected elements (need count/list of selected?) -- */ PerturbationType createPerturbation (PointerListType *selected, double T) { PerturbationType pt = { 0 }; /* pick element to perturb */ pt.element = (ElementType *) selected->Ptr[random () % selected->PtrN]; /* exchange, flip/rotate or shift? */ switch (random () % ((selected->PtrN > 1) ? 3 : 2)) { case 0: { /* shift! */ Coord grid; double scaleX = CLAMP (sqrt (T), MIL_TO_COORD (2.5), PCB->MaxWidth / 3); double scaleY = CLAMP (sqrt (T), MIL_TO_COORD (2.5), PCB->MaxHeight / 3); pt.which = SHIFT; pt.DX = scaleX * 2 * ((((double) random ()) / RAND_MAX) - 0.5); pt.DY = scaleY * 2 * ((((double) random ()) / RAND_MAX) - 0.5); /* snap to grid. different grids for "high" and "low" T */ grid = (T > MIL_TO_COORD (10)) ? CostParameter.large_grid_size : CostParameter.small_grid_size; /* (round away from zero) */ pt.DX = ((pt.DX / grid) + SGN (pt.DX)) * grid; pt.DY = ((pt.DY / grid) + SGN (pt.DY)) * grid; /* limit DX/DY so we don't fall off board */ pt.DX = MAX (pt.DX, -pt.element->VBox.X1); pt.DX = MIN (pt.DX, PCB->MaxWidth - pt.element->VBox.X2); pt.DY = MAX (pt.DY, -pt.element->VBox.Y1); pt.DY = MIN (pt.DY, PCB->MaxHeight - pt.element->VBox.Y2); /* all done but the movin' */ break; } case 1: { /* flip/rotate! */ /* only flip if it's an SMD component */ bool isSMD = pt.element->PadN != 0; pt.which = ROTATE; pt.rotate = isSMD ? (random () & 3) : (1 + (random () % 3)); /* 0 - flip; 1-3, rotate. */ break; } case 2: { /* exchange! */ pt.which = EXCHANGE; pt.other = (ElementType *) selected->Ptr[random () % (selected->PtrN - 1)]; if (pt.other == pt.element) pt.other = (ElementType *) selected->Ptr[selected->PtrN - 1]; /* don't allow exchanging a solderside-side SMD component * with a non-SMD component. */ if ((pt.element->PinN != 0 /* non-SMD */ && TEST_FLAG (ONSOLDERFLAG, pt.other)) || (pt.other->PinN != 0 /* non-SMD */ && TEST_FLAG (ONSOLDERFLAG, pt.element))) return createPerturbation (selected, T); break; } default: assert (0); } return pt; }
CostParameter = { 3e3, /* via cost */ 2e-2, /* congestion penalty */ 1e-2, /* initial overlap penalty */ 1e2, /* final overlap penalty */ 1e3, /* out of bounds penalty */ 1e0, /* penalty for total area used */ 1e0, /* subtract 1000 from cost for every same-type neighbor */ 1e0, /* subtract 1000 from cost for every aligned neighbor */ 1e0, /* subtract 1000 from cost for every same-rotation neighbor */ 20, /* move on when each module has been profitably moved 20 times */ 0.75, /* annealing schedule constant: 0.85 */ 40, /* halt when there are 60 times as many moves as good moves */ false, /* don't ignore SMD/pin conflicts */ MIL_TO_COORD (100), /* coarse grid is 100 mils */ MIL_TO_COORD (10), /* fine grid is 10 mils */ }; typedef struct { ElementType **element; Cardinal elementN; } ElementPtrListType; enum ewhich { SHIFT, ROTATE, EXCHANGE }; typedef struct {
Nanometer @item in Inch (1in = 0.0254m) @item mil Mil (1000mil = 1in) @item cmil Centimil (1/100 mil) @end table @ftable @code @item --via-thickness <num> Default diameter of vias. Default value is @code{60mil}. @end ftable %end-doc */ CSET (ViaThickness, MIL_TO_COORD(60), "via-thickness", "default diameter of vias in 1/100 mil"), /* %start-doc options "5 Sizes" @ftable @code @item --via-drilling-hole <num> Default diameter of holes. Default value is @code{28mil}. @end ftable %end-doc */ CSET (ViaDrillingHole, MIL_TO_COORD(28), "via-drilling-hole", "default diameter of holes"), /* %start-doc options "5 Sizes" @ftable @code @item --line-thickness <num>
int ActionLoadVendorFrom (int argc, char **argv, Coord x, Coord y) { int i; char *fname = NULL; static char *default_file = NULL; char *sval; Resource *res, *drcres, *drlres; int type; bool free_fname = false; cached_drill = -1; fname = argc ? argv[0] : 0; if (!fname || !*fname) { fname = gui->fileselect (_("Load Vendor Resource File..."), _("Picks a vendor resource file to load.\n" "This file can contain drc settings for a\n" "particular vendor as well as a list of\n" "predefined drills which are allowed."), default_file, ".res", "vendor", HID_FILESELECT_READ); if (fname == NULL) AFAIL (load_vendor); free_fname = true; free (default_file); default_file = NULL; if (fname && *fname) default_file = strdup (fname); } /* Unload any vendor table we may have had */ n_vendor_drills = 0; n_refdes = 0; n_value = 0; n_descr = 0; FREE (vendor_drills); FREE (ignore_refdes); FREE (ignore_value); FREE (ignore_descr); /* load the resource file */ res = resource_parse (fname, NULL); if (res == NULL) { Message (_("Could not load vendor resource file \"%s\"\n"), fname); return 1; } /* figure out the vendor name, if specified */ vendor_name = (char *)UNKNOWN (resource_value (res, "vendor")); /* figure out the units, if specified */ sval = resource_value (res, "units"); if (sval == NULL) { sf = MIL_TO_COORD(1); } else if ((NSTRCMP (sval, "mil") == 0) || (NSTRCMP (sval, "mils") == 0)) { sf = MIL_TO_COORD(1); } else if ((NSTRCMP (sval, "inch") == 0) || (NSTRCMP (sval, "inches") == 0)) { sf = INCH_TO_COORD(1); } else if (NSTRCMP (sval, "mm") == 0) { sf = MM_TO_COORD(1); } else { Message ("\"%s\" is not a supported units. Defaulting to inch\n", sval); sf = INCH_TO_COORD(1); } /* default to ROUND_UP */ rounding_method = ROUND_UP; /* extract the drillmap resource */ drlres = resource_subres (res, "drillmap"); if (drlres == NULL) { Message (_("No drillmap resource found\n")); } else { sval = resource_value (drlres, "round"); if (sval != NULL) { if (NSTRCMP (sval, "up") == 0) { rounding_method = ROUND_UP; } else if (NSTRCMP (sval, "nearest") == 0) { rounding_method = CLOSEST; } else { Message (_ ("\"%s\" is not a valid rounding type. Defaulting to up\n"), sval); rounding_method = ROUND_UP; } } process_skips (resource_subres (drlres, "skips")); for (i = 0; i < drlres->c; i++) { type = resource_type (drlres->v[i]); switch (type) { case 10: /* just a number */ add_to_drills (drlres->v[i].value); break; default: break; } } } /* Extract the DRC resource */ drcres = resource_subres (res, "drc"); sval = resource_value (drcres, "copper_space"); if (sval != NULL) { PCB->Bloat = floor (sf * atof (sval) + 0.5); Message (_("Set DRC minimum copper spacing to %.2f mils\n"), 0.01 * PCB->Bloat); } sval = resource_value (drcres, "copper_overlap"); if (sval != NULL) { PCB->Shrink = floor (sf * atof (sval) + 0.5); Message (_("Set DRC minimum copper overlap to %.2f mils\n"), 0.01 * PCB->Shrink); } sval = resource_value (drcres, "copper_width"); if (sval != NULL) { PCB->minWid = floor (sf * atof (sval) + 0.5); Message (_("Set DRC minimum copper spacing to %.2f mils\n"), 0.01 * PCB->minWid); } sval = resource_value (drcres, "silk_width"); if (sval != NULL) { PCB->minSlk = floor (sf * atof (sval) + 0.5); Message (_("Set DRC minimum silk width to %.2f mils\n"), 0.01 * PCB->minSlk); } sval = resource_value (drcres, "min_drill"); if (sval != NULL) { PCB->minDrill = floor (sf * atof (sval) + 0.5); Message (_("Set DRC minimum drill diameter to %.2f mils\n"), 0.01 * PCB->minDrill); } sval = resource_value (drcres, "min_ring"); if (sval != NULL) { PCB->minRing = floor (sf * atof (sval) + 0.5); Message (_("Set DRC minimum annular ring to %.2f mils\n"), 0.01 * PCB->minRing); } Message (_("Loaded %d vendor drills from %s\n"), n_vendor_drills, fname); Message (_("Loaded %d RefDes skips, %d Value skips, %d Descr skips\n"), n_refdes, n_value, n_descr); vendorMapEnable = true; apply_vendor_map (); if (free_fname) free (fname); return 0; }
/* --------------------------------------------------------------------------- * recalculates the passed coordinates to fit the current grid setting */ void FitCrosshairIntoGrid (Coord X, Coord Y) { Coord nearest_grid_x, nearest_grid_y; void *ptr1, *ptr2, *ptr3; struct snap_data snap_data; int ans; Crosshair.X = CLAMP (X, Crosshair.MinX, Crosshair.MaxX); Crosshair.Y = CLAMP (Y, Crosshair.MinY, Crosshair.MaxY); if (PCB->RatDraw) { nearest_grid_x = -MIL_TO_COORD (6); nearest_grid_y = -MIL_TO_COORD (6); } else { nearest_grid_x = GridFit (Crosshair.X, PCB->Grid, PCB->GridOffsetX); nearest_grid_y = GridFit (Crosshair.Y, PCB->Grid, PCB->GridOffsetY); if (Marked.status && TEST_FLAG (ORTHOMOVEFLAG, PCB)) { Coord dx = Crosshair.X - Marked.X; Coord dy = Crosshair.Y - Marked.Y; if (ABS (dx) > ABS (dy)) nearest_grid_y = Marked.Y; else nearest_grid_x = Marked.X; } } snap_data.crosshair = &Crosshair; snap_data.nearest_sq_dist = crosshair_sq_dist (&Crosshair, nearest_grid_x, nearest_grid_y); snap_data.nearest_is_grid = true; snap_data.x = nearest_grid_x; snap_data.y = nearest_grid_y; ans = NO_TYPE; if (!PCB->RatDraw) ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y, ELEMENT_TYPE, &ptr1, &ptr2, &ptr3); if (ans & ELEMENT_TYPE) { ElementType *el = (ElementType *) ptr1; check_snap_object (&snap_data, el->MarkX, el->MarkY, false); } ans = NO_TYPE; if (PCB->RatDraw || TEST_FLAG (SNAPPINFLAG, PCB)) ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y, PAD_TYPE, &ptr1, &ptr2, &ptr3); /* Avoid self-snapping when moving */ if (ans != NO_TYPE && Settings.Mode == MOVE_MODE && Crosshair.AttachedObject.Type == ELEMENT_TYPE && ptr1 == Crosshair.AttachedObject.Ptr1) ans = NO_TYPE; if (ans != NO_TYPE && ( Settings.Mode == LINE_MODE || (Settings.Mode == MOVE_MODE && Crosshair.AttachedObject.Type == LINEPOINT_TYPE))) { PadTypePtr pad = (PadTypePtr) ptr2; LayerType *desired_layer; Cardinal desired_group; Cardinal SLayer, CLayer; int found_our_layer = false; desired_layer = CURRENT; if (Settings.Mode == MOVE_MODE && Crosshair.AttachedObject.Type == LINEPOINT_TYPE) { desired_layer = (LayerType *)Crosshair.AttachedObject.Ptr1; } /* find layer groups of the component side and solder side */ SLayer = GetLayerGroupNumberByNumber (solder_silk_layer); CLayer = GetLayerGroupNumberByNumber (component_silk_layer); desired_group = TEST_FLAG (ONSOLDERFLAG, pad) ? SLayer : CLayer; GROUP_LOOP (PCB->Data, desired_group); { if (layer == desired_layer) { found_our_layer = true; break; } } END_LOOP; if (found_our_layer == false) ans = NO_TYPE; } if (ans != NO_TYPE) { PadType *pad = (PadType *)ptr2; check_snap_object (&snap_data, (pad->Point1.X + pad->Point2.X) / 2, (pad->Point1.Y + pad->Point2.Y) / 2, true); } ans = NO_TYPE; if (PCB->RatDraw || TEST_FLAG (SNAPPINFLAG, PCB)) ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y, PIN_TYPE, &ptr1, &ptr2, &ptr3); /* Avoid self-snapping when moving */ if (ans != NO_TYPE && Settings.Mode == MOVE_MODE && Crosshair.AttachedObject.Type == ELEMENT_TYPE && ptr1 == Crosshair.AttachedObject.Ptr1) ans = NO_TYPE; if (ans != NO_TYPE) { PinType *pin = (PinType *)ptr2; check_snap_object (&snap_data, pin->X, pin->Y, true); } ans = NO_TYPE; if (TEST_FLAG (SNAPPINFLAG, PCB)) ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y, VIA_TYPE, &ptr1, &ptr2, &ptr3); /* Avoid snapping vias to any other vias */ if (Settings.Mode == MOVE_MODE && Crosshair.AttachedObject.Type == VIA_TYPE && (ans & PIN_TYPES)) ans = NO_TYPE; if (ans != NO_TYPE) { PinType *pin = (PinType *)ptr2; check_snap_object (&snap_data, pin->X, pin->Y, true); } ans = NO_TYPE; if (TEST_FLAG (SNAPPINFLAG, PCB)) ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y, LINEPOINT_TYPE, &ptr1, &ptr2, &ptr3); if (ans != NO_TYPE) { PointType *pnt = (PointType *)ptr3; check_snap_object (&snap_data, pnt->X, pnt->Y, true); } check_snap_offgrid_line (&snap_data, nearest_grid_x, nearest_grid_y); ans = NO_TYPE; if (TEST_FLAG (SNAPPINFLAG, PCB)) ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y, POLYGONPOINT_TYPE, &ptr1, &ptr2, &ptr3); if (ans != NO_TYPE) { PointType *pnt = (PointType *)ptr3; check_snap_object (&snap_data, pnt->X, pnt->Y, true); } if (snap_data.x >= 0 && snap_data.y >= 0) { Crosshair.X = snap_data.x; Crosshair.Y = snap_data.y; } if (Settings.Mode == ARROW_MODE) { ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y, LINEPOINT_TYPE, &ptr1, &ptr2, &ptr3); if (ans == NO_TYPE) hid_action("PointCursor"); else if (!TEST_FLAG(SELECTEDFLAG, (LineType *)ptr2)) hid_actionl("PointCursor","True", NULL); } if (Settings.Mode == LINE_MODE && Crosshair.AttachedLine.State != STATE_FIRST && TEST_FLAG (AUTODRCFLAG, PCB)) EnforceLineDRC (); gui->set_crosshair (Crosshair.X, Crosshair.Y, HID_SC_DO_NOTHING); }
static int FontEdit (int argc, char **argv, Coord Ux, Coord Uy) { FontType *font; SymbolType *symbol; LayerType *lfont, *lorig, *lwidth, *lgrid; int s, l; if (hid_actionl ("New", "Font", 0)) { return 1; } Settings.grid_unit = get_unit_struct("mil"); Settings.Bloat = PCB->Bloat = 1; Settings.Shrink = PCB->Shrink = 1; Settings.minWid = PCB->minWid = 1; Settings.minSlk = PCB->minSlk = 1; MoveLayerToGroup (max_copper_layer + TOP_SILK_LAYER, 0); MoveLayerToGroup (max_copper_layer + BOTTOM_SILK_LAYER, 1); while (PCB->Data->LayerN > 4) { MoveLayer (4, -1); } for (l = 0; l < 4; l++) { MoveLayerToGroup (l, l); } PCB->MaxWidth = CELL_SIZE * 18; PCB->MaxHeight = CELL_SIZE * ((MAX_FONTPOSITION + 15) / 16 + 2); PCB->Grid = MIL_TO_COORD (5); PCB->Data->Layer[0].Name = strdup ("Font"); PCB->Data->Layer[1].Name = strdup ("OrigFont"); PCB->Data->Layer[2].Name = strdup ("Width"); PCB->Data->Layer[3].Name = strdup ("Grid"); hid_action ("PCBChanged"); hid_action ("LayersChanged"); lfont = PCB->Data->Layer + 0; lorig = PCB->Data->Layer + 1; lwidth = PCB->Data->Layer + 2; lgrid = PCB->Data->Layer + 3; font = &PCB->Font; for (s = 0; s <= MAX_FONTPOSITION; s++) { Coord ox = (s % 16 + 1) * CELL_SIZE; Coord oy = (s / 16 + 1) * CELL_SIZE; Coord w, miny, maxy, maxx = 0; symbol = &font->Symbol[s]; miny = MIL_TO_COORD (5); maxy = font->MaxHeight; for (l = 0; l < symbol->LineN; l++) { CreateDrawnLineOnLayer (lfont, symbol->Line[l].Point1.X + ox, symbol->Line[l].Point1.Y + oy, symbol->Line[l].Point2.X + ox, symbol->Line[l].Point2.Y + oy, symbol->Line[l].Thickness, symbol->Line[l].Thickness, NoFlags ()); CreateDrawnLineOnLayer (lorig, symbol->Line[l].Point1.X + ox, symbol->Line[l].Point1.Y + oy, symbol->Line[l].Point2.X + ox, symbol->Line[l].Point2.Y + oy, symbol->Line[l].Thickness, symbol->Line[l].Thickness, NoFlags ()); if (maxx < symbol->Line[l].Point1.X) { maxx = symbol->Line[l].Point1.X; } if (maxx < symbol->Line[l].Point2.X) { maxx = symbol->Line[l].Point2.X; } } w = maxx + symbol->Delta + ox; CreateDrawnLineOnLayer (lwidth, w, miny + oy, w, maxy + oy, MIL_TO_COORD (1), MIL_TO_COORD (1), NoFlags ()); } for (l = 0; l < 16; l++) { int x = (l + 1) * CELL_SIZE; CreateDrawnLineOnLayer (lgrid, x, 0, x, PCB->MaxHeight, MIL_TO_COORD (1), MIL_TO_COORD (1), NoFlags ()); } for (l = 0; l <= MAX_FONTPOSITION / 16 + 1; l++) { int y = (l + 1) * CELL_SIZE; CreateDrawnLineOnLayer (lgrid, 0, y, PCB->MaxWidth, y, MIL_TO_COORD (1), MIL_TO_COORD (1), NoFlags ()); } return 0; }