/*! * \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; }
/*! * \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; }; }
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; }
/* --------------------------------------------------------------------------- * 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 (); }
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); }
/* * 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; }
/* --------------------------------------------------------------------------- * 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++); }
/* --------------------------------------------------------------------------- * 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; }
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. */ }
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); }
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; }
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; }
/* 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; }
/* --------------------------------------------------------------------------- * 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; }
/*! * \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; }
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; }
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; }
/*! * \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; }
/* * 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; }
/* --------------------------------------------------------------------------- * 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); }
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; }
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; }
/* %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; }
/* --------------------------------------------------------------------------- * 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; }
/* --------------------------------------------------------------------------- * 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); }
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; }
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; }
/* --------------------------------------------------------------------------- * 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)); }
/* * 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; }
/* --------------------------------------------------------------------------- * 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); }