/* --------------------------------------------------------------------------- * get next slot for a pin, allocates memory if necessary */ PinTypePtr GetPinMemory (ElementTypePtr Element) { PinTypePtr pin = Element->Pin; bool onBoard = false; /* realloc new memory if necessary and clear it */ if (Element->PinN >= Element->PinMax) { if (PCB->Data->pin_tree) { PIN_LOOP (Element); { if (r_delete_entry (PCB->Data->pin_tree, (BoxType *) pin)) onBoard = true; } END_LOOP; } Element->PinMax += STEP_PIN; pin = MyRealloc (pin, Element->PinMax * sizeof (PinType), "GetPinMemory()"); Element->Pin = pin; memset (pin + Element->PinN, 0, STEP_PIN * sizeof (PinType)); if (onBoard) { PIN_LOOP (Element); { r_insert_entry (PCB->Data->pin_tree, (BoxType *) pin, 0); } END_LOOP; } } return (pin + Element->PinN++); }
/* --------------------------------------------------------------------------- * frees memory used by an element */ void FreeElementMemory (ElementTypePtr Element) { if (Element) { ELEMENTNAME_LOOP (Element); { MYFREE (textstring); } END_LOOP; PIN_LOOP (Element); { MYFREE (pin->Name); MYFREE (pin->Number); } END_LOOP; PAD_LOOP (Element); { MYFREE (pad->Name); MYFREE (pad->Number); } END_LOOP; MYFREE (Element->Pin); MYFREE (Element->Pad); MYFREE (Element->Line); MYFREE (Element->Arc); FreeAttributeListMemory (&Element->Attributes); memset (Element, 0, sizeof (ElementType)); } }
/* --------------------------------------------------------------------------- * frees memory used by an element */ void FreeElementMemory (ElementType *element) { if (element == NULL) return; ELEMENTNAME_LOOP (element); { free (textstring); } END_LOOP; PIN_LOOP (element); { free (pin->Name); free (pin->Number); } END_LOOP; PAD_LOOP (element); { free (pad->Name); free (pad->Number); } END_LOOP; g_list_free_full (element->Pin, (GDestroyNotify)FreePin); g_list_free_full (element->Pad, (GDestroyNotify)FreePad); g_list_free_full (element->Line, (GDestroyNotify)FreeLine); g_list_free_full (element->Arc, (GDestroyNotify)FreeArc); FreeAttributeListMemory (&element->Attributes); memset (element, 0, sizeof (ElementType)); }
void log_element(ElementType *e) { base_log("Element\n"); base_log("Description: %s\n", DESCRIPTION_NAME(e)); base_log("Name on PCB: %s\n", NAMEONPCB_NAME(e)); base_log("Value: %s\n", VALUE_NAME(e)); base_log("Flags: %04x\n", FLAG_VALUE(e->Flags)); base_log("MarkX, MarkY: %d, %d\n", e->MarkX, e->MarkY); base_log("PinN: %d\n", e->PinN); base_log("PadN: %d\n", e->PadN); base_log("LineN: %d\n", e->LineN); base_log("ArcN: %d\n", e->ArcN); base_log("Attributes number: %d\n", e->Attributes.Number); int i = 0; PAD_LOOP(e); { base_log("Pad %d\n", i++); log_pad(pad); } END_LOOP; i = 0; PIN_LOOP(e); { base_log("Pin %d\n", i++); log_pin(pin); } END_LOOP; }
void FreeRotateElementLowLevel (DataType *Data, ElementType *Element, Coord X, Coord Y, double cosa, double sina, Angle angle) { /* solder side objects need a different orientation */ /* the text subroutine decides by itself if the direction * is to be corrected */ #if 0 ELEMENTTEXT_LOOP (Element); { if (Data && Data->name_tree[n]) r_delete_entry (Data->name_tree[n], (BoxType *)text); RotateTextLowLevel (text, X, Y, Number); } END_LOOP; #endif ELEMENTLINE_LOOP (Element); { free_rotate (&line->Point1.X, &line->Point1.Y, X, Y, cosa, sina); free_rotate (&line->Point2.X, &line->Point2.Y, X, Y, cosa, sina); SetLineBoundingBox (line); } END_LOOP; PIN_LOOP (Element); { /* pre-delete the pins from the pin-tree before their coordinates change */ if (Data) r_delete_entry (Data->pin_tree, (BoxType *)pin); RestoreToPolygon (Data, PIN_TYPE, Element, pin); free_rotate (&pin->X, &pin->Y, X, Y, cosa, sina); SetPinBoundingBox (pin); } END_LOOP; PAD_LOOP (Element); { /* pre-delete the pads before their coordinates change */ if (Data) r_delete_entry (Data->pad_tree, (BoxType *)pad); RestoreToPolygon (Data, PAD_TYPE, Element, pad); free_rotate (&pad->Point1.X, &pad->Point1.Y, X, Y, cosa, sina); free_rotate (&pad->Point2.X, &pad->Point2.Y, X, Y, cosa, sina); SetLineBoundingBox ((LineType *) pad); } END_LOOP; ARC_LOOP (Element); { free_rotate (&arc->X, &arc->Y, X, Y, cosa, sina); arc->StartAngle = NormalizeAngle (arc->StartAngle + angle); } END_LOOP; free_rotate (&Element->MarkX, &Element->MarkY, X, Y, cosa, sina); SetElementBoundingBox (Data, Element, &PCB->Font); ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element); }
/* --------------------------------------------------------------------------- * moves a element to buffer without allocating memory for pins/names */ static void * MoveElementToBuffer (ElementType *element) { /* * Delete the element from the source (remove it from trees, * restore to polygons) */ r_delete_element (Source, element); Source->Element = g_list_remove (Source->Element, element); Source->ElementN --; Dest->Element = g_list_append (Dest->Element, element); Dest->ElementN ++; PIN_LOOP (element); { RestoreToPolygon(Source, PIN_TYPE, element, pin); CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, pin); } END_LOOP; PAD_LOOP (element); { RestoreToPolygon(Source, PAD_TYPE, element, pad); CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, pad); } END_LOOP; SetElementBoundingBox (Dest, element, &PCB->Font); /* * Now clear the from the polygons in the destination */ PIN_LOOP (element); { ClearFromPolygon (Dest, PIN_TYPE, element, pin); } END_LOOP; PAD_LOOP (element); { ClearFromPolygon (Dest, PAD_TYPE, element, pad); } END_LOOP; return element; }
/* --------------------------------------------------------------------------- * mirrors the coordinates of an element * an additional offset is passed */ void MirrorElementCoordinates (DataTypePtr Data, ElementTypePtr Element, Coord yoff) { r_delete_element (Data, Element); ELEMENTLINE_LOOP (Element); { line->Point1.X = SWAP_X (line->Point1.X); line->Point1.Y = SWAP_Y (line->Point1.Y) + yoff; line->Point2.X = SWAP_X (line->Point2.X); line->Point2.Y = SWAP_Y (line->Point2.Y) + yoff; } END_LOOP; PIN_LOOP (Element); { RestoreToPolygon (Data, PIN_TYPE, Element, pin); pin->X = SWAP_X (pin->X); pin->Y = SWAP_Y (pin->Y) + yoff; } END_LOOP; PAD_LOOP (Element); { RestoreToPolygon (Data, PAD_TYPE, Element, pad); pad->Point1.X = SWAP_X (pad->Point1.X); pad->Point1.Y = SWAP_Y (pad->Point1.Y) + yoff; pad->Point2.X = SWAP_X (pad->Point2.X); pad->Point2.Y = SWAP_Y (pad->Point2.Y) + yoff; TOGGLE_FLAG (ONSOLDERFLAG, pad); } END_LOOP; ARC_LOOP (Element); { arc->X = SWAP_X (arc->X); arc->Y = SWAP_Y (arc->Y) + yoff; arc->StartAngle = SWAP_ANGLE (arc->StartAngle); arc->Delta = SWAP_DELTA (arc->Delta); } END_LOOP; ELEMENTTEXT_LOOP (Element); { text->X = SWAP_X (text->X); text->Y = SWAP_Y (text->Y) + yoff; TOGGLE_FLAG (ONSOLDERFLAG, text); } END_LOOP; Element->MarkX = SWAP_X (Element->MarkX); Element->MarkY = SWAP_Y (Element->MarkY) + yoff; /* now toggle the solder-side flag */ TOGGLE_FLAG (ONSOLDERFLAG, Element); /* this inserts all of the rtree data too */ SetElementBoundingBox (Data, Element, &PCB->Font); ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element); }
PinType * find_pin (ElementType *element, const char* number) { PIN_LOOP(element); { if (pin->Number && number_cmp(pin->Number, number) == 0) { return pin; } } END_LOOP; return NULL; }
/* --------------------------------------------------------------------------- * erases all pins and pads of an element */ void EraseElementPinsAndPads (ElementType *Element) { PIN_LOOP (Element); { ErasePin (pin); } END_LOOP; PAD_LOOP (Element); { ErasePad (pad); } END_LOOP; }
/* --------------------------------------------------------------------------- * 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++); }
/* --------------------------------------------------------------------------- * draw pins of an element */ void DrawElementPinsAndPads (ElementType *Element) { PAD_LOOP (Element); { if (doing_pinout || doing_assy || FRONT (pad) || PCB->InvisibleObjectsOn) DrawPad (pad); } END_LOOP; PIN_LOOP (Element); { DrawPin (pin); } END_LOOP; }
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 draw_element_pins_and_pads (ElementType *element) { PAD_LOOP (element); { if (doing_pinout || doing_assy || FRONT (pad) || PCB->InvisibleObjectsOn) draw_pad (pad); } END_LOOP; PIN_LOOP (element); { draw_pin (pin, true); } END_LOOP; }
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 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; }
void LookupRatLines (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { switch (Type) { case ELEMENT_TYPE: { ElementType *element = (ElementType *) Ptr1; PIN_LOOP (element); { CheckPinForRat (pin); } END_LOOP; PAD_LOOP (element); { CheckPadForRat (pad); } END_LOOP; break; } case LINE_TYPE: { LayerType *layer = (LayerType *) Ptr1; LineType *line = (LineType *) Ptr2; CheckLinePointForRat (layer, &line->Point1); CheckLinePointForRat (layer, &line->Point2); break; } case LINEPOINT_TYPE: CheckLinePointForRat ((LayerType *) Ptr1, (PointType *) Ptr3); break; case VIA_TYPE: CheckPinForRat ((PinType *) Ptr1); break; } }
/* --------------------------------------------------------------------------- * destroys a element */ static void * DestroyElement (ElementTypePtr Element) { if (DestroyTarget->element_tree) r_delete_entry (DestroyTarget->element_tree, (BoxType *) Element); if (DestroyTarget->pin_tree) { PIN_LOOP (Element); { r_delete_entry (DestroyTarget->pin_tree, (BoxType *) pin); } END_LOOP; } if (DestroyTarget->pad_tree) { PAD_LOOP (Element); { r_delete_entry (DestroyTarget->pad_tree, (BoxType *) pad); } END_LOOP; } ELEMENTTEXT_LOOP (Element); { if (DestroyTarget->name_tree[n]) r_delete_entry (DestroyTarget->name_tree[n], (BoxType *) text); } END_LOOP; FreeElementMemory (Element); DestroyTarget->Element = g_list_remove (DestroyTarget->Element, Element); DestroyTarget->ElementN --; g_slice_free (ElementType, Element); return NULL; }
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; }
static int ReportDialog (int argc, char **argv, Coord x, Coord y) { void *ptr1, *ptr2, *ptr3; int type; char report[2048]; type = SearchScreen (x, y, REPORT_TYPES, &ptr1, &ptr2, &ptr3); if (type == NO_TYPE) type = SearchScreen (x, y, REPORT_TYPES | LOCKED_TYPE, &ptr1, &ptr2, &ptr3); switch (type) { case VIA_TYPE: { PinType *via; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->via_tree->root, 0); return 0; } #endif via = (PinType *) ptr2; if (TEST_FLAG (HOLEFLAG, via)) pcb_snprintf (report, sizeof (report), _("%m+VIA ID# %ld; Flags:%s\n" "(X,Y) = %$mD.\n" "It is a pure hole of diameter %$mS.\n" "Name = \"%s\"." "%s"), USER_UNITMASK, via->ID, flags_to_string (via->Flags, VIA_TYPE), via->X, via->Y, via->DrillingHole, EMPTY (via->Name), TEST_FLAG (LOCKFLAG, via) ? _("It is LOCKED.\n") : ""); else pcb_snprintf (report, sizeof (report), _("%m+VIA ID# %ld; Flags:%s\n" "(X,Y) = %$mD.\n" "Copper width = %$mS. Drill width = %$mS.\n" "Clearance width in polygons = %$mS.\n" "Annulus = %$mS.\n" "Solder mask hole = %$mS (gap = %$mS).\n" "Name = \"%s\"." "%s"), USER_UNITMASK, via->ID, flags_to_string (via->Flags, VIA_TYPE), via->X, via->Y, via->Thickness, via->DrillingHole, via->Clearance / 2, (via->Thickness - via->DrillingHole) / 2, via->Mask, (via->Mask - via->Thickness) / 2, EMPTY (via->Name), TEST_FLAG (LOCKFLAG, via) ? _("It is LOCKED.\n") : ""); break; } case PIN_TYPE: { PinType *Pin; ElementType *element; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->pin_tree->root, 0); return 0; } #endif Pin = (PinType *) ptr2; element = (ElementType *) ptr1; PIN_LOOP (element); { if (pin == Pin) break; } END_LOOP; if (TEST_FLAG (HOLEFLAG, Pin)) pcb_snprintf (report, sizeof (report), _("%m+PIN ID# %ld; Flags:%s\n" "(X,Y) = %$mD.\n" "It is a mounting hole. Drill width = %$mS.\n" "It is owned by element %$mS.\n" "%s"), USER_UNITMASK, Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE), Pin->X, Pin->Y, Pin->DrillingHole, EMPTY (element->Name[1].TextString), TEST_FLAG (LOCKFLAG, Pin) ? _("It is LOCKED.\n") : ""); else pcb_snprintf (report, sizeof (report), _("%m+PIN ID# %ld; Flags:%s\n" "(X,Y) = %$mD.\n" "Copper width = %$mS. Drill width = %$mS.\n" "Clearance width to Polygon = %$mS.\n" "Annulus = %$mS.\n" "Solder mask hole = %$mS (gap = %$mS).\n" "Name = \"%s\".\n" "It is owned by element %s\n as pin number %s.\n" "%s"), USER_UNITMASK, Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE), Pin->X, Pin->Y, Pin->Thickness, Pin->DrillingHole, Pin->Clearance / 2, (Pin->Thickness - Pin->DrillingHole) / 2, Pin->Mask, (Pin->Mask - Pin->Thickness) / 2, EMPTY (Pin->Name), EMPTY (element->Name[1].TextString), EMPTY (Pin->Number), TEST_FLAG (LOCKFLAG, Pin) ? _("It is LOCKED.\n") : ""); break; } case LINE_TYPE: { LineType *line; #ifndef NDEBUG if (gui->shift_is_pressed ()) { LayerType *layer = (LayerType *) ptr1; __r_dump_tree (layer->line_tree->root, 0); return 0; } #endif line = (LineType *) ptr2; pcb_snprintf (report, sizeof (report), _("%m+LINE ID# %ld; Flags:%s\n" "FirstPoint(X,Y) = %$mD, ID = %ld.\n" "SecondPoint(X,Y) = %$mD, ID = %ld.\n" "Width = %$mS.\nClearance width in polygons = %$mS.\n" "It is on layer %d\n" "and has name \"%s\".\n" "%s"), USER_UNITMASK, line->ID, flags_to_string (line->Flags, LINE_TYPE), line->Point1.X, line->Point1.Y, line->Point1.ID, line->Point2.X, line->Point2.Y, line->Point2.ID, line->Thickness, line->Clearance / 2, GetLayerNumber (PCB->Data, (LayerType *) ptr1), UNKNOWN (line->Number), TEST_FLAG (LOCKFLAG, line) ? _("It is LOCKED.\n") : ""); break; } case RATLINE_TYPE: { RatType *line; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->rat_tree->root, 0); return 0; } #endif line = (RatType *) ptr2; pcb_snprintf (report, sizeof (report), _("%m+RAT-LINE ID# %ld; Flags:%s\n" "FirstPoint(X,Y) = %$mD; ID = %ld; " "connects to layer group %d.\n" "SecondPoint(X,Y) = %$mD; ID = %ld; " "connects to layer group %d.\n"), USER_UNITMASK, line->ID, flags_to_string (line->Flags, LINE_TYPE), line->Point1.X, line->Point1.Y, line->Point1.ID, line->group1, line->Point2.X, line->Point2.Y, line->Point2.ID, line->group2); break; } case ARC_TYPE: { ArcType *Arc; BoxType *box; #ifndef NDEBUG if (gui->shift_is_pressed ()) { LayerType *layer = (LayerType *) ptr1; __r_dump_tree (layer->arc_tree->root, 0); return 0; } #endif Arc = (ArcType *) ptr2; box = GetArcEnds (Arc); pcb_snprintf (report, sizeof (report), _("%m+ARC ID# %ld; Flags:%s\n" "CenterPoint(X,Y) = %$mD.\n" "Radius = %$mS, Thickness = %$mS.\n" "Clearance width in polygons = %$mS.\n" "StartAngle = %ma degrees, DeltaAngle = %ma degrees.\n" "Bounding Box is %$mD, %$mD.\n" "That makes the end points at %$mD and %$mD.\n" "It is on layer %d.\n" "%s"), USER_UNITMASK, Arc->ID, flags_to_string (Arc->Flags, ARC_TYPE), Arc->X, Arc->Y, Arc->Width, Arc->Thickness, Arc->Clearance / 2, Arc->StartAngle, Arc->Delta, Arc->BoundingBox.X1, Arc->BoundingBox.Y1, Arc->BoundingBox.X2, Arc->BoundingBox.Y2, box->X1, box->Y1, box->X2, box->Y2, GetLayerNumber (PCB->Data, (LayerType *) ptr1), TEST_FLAG (LOCKFLAG, Arc) ? _("It is LOCKED.\n") : ""); break; } case POLYGON_TYPE: { PolygonType *Polygon; #ifndef NDEBUG if (gui->shift_is_pressed ()) { LayerType *layer = (LayerType *) ptr1; __r_dump_tree (layer->polygon_tree->root, 0); return 0; } #endif Polygon = (PolygonType *) ptr2; pcb_snprintf (report, sizeof (report), _("%m+POLYGON ID# %ld; Flags:%s\n" "Its bounding box is %$mD %$mD.\n" "It has %d points and could store %d more\n" " without using more memory.\n" "It has %d holes and resides on layer %d.\n" "%s"), USER_UNITMASK, Polygon->ID, flags_to_string (Polygon->Flags, POLYGON_TYPE), Polygon->BoundingBox.X1, Polygon->BoundingBox.Y1, Polygon->BoundingBox.X2, Polygon->BoundingBox.Y2, Polygon->PointN, Polygon->PointMax - Polygon->PointN, Polygon->HoleIndexN, GetLayerNumber (PCB->Data, (LayerType *) ptr1), TEST_FLAG (LOCKFLAG, Polygon) ? _("It is LOCKED.\n") : ""); break; } case PAD_TYPE: { Coord len; PadType *Pad; ElementType *element; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->pad_tree->root, 0); return 0; } #endif Pad = (PadType *) ptr2; element = (ElementType *) ptr1; PAD_LOOP (element); { { if (pad == Pad) break; } } END_LOOP; len = Distance (Pad->Point1.X, Pad->Point1.Y, Pad->Point2.X, Pad->Point2.Y); pcb_snprintf (report, sizeof (report), _("%m+PAD ID# %ld; Flags:%s\n" "FirstPoint(X,Y) = %$mD; ID = %ld.\n" "SecondPoint(X,Y) = %$mD; ID = %ld.\n" "Width = %$mS. Length = %$mS.\n" "Clearance width in polygons = %$mS.\n" "Solder mask = %$mS x %$mS (gap = %$mS).\n" "Name = \"%s\".\n" "It is owned by SMD element %s\n" " as pin number %s and is on the %s\n" "side of the board.\n" "%s"), USER_UNITMASK, Pad->ID, flags_to_string (Pad->Flags, PAD_TYPE), Pad->Point1.X, Pad->Point1.Y, Pad->Point1.ID, Pad->Point2.X, Pad->Point2.Y, Pad->Point2.ID, Pad->Thickness, len + Pad->Thickness, Pad->Clearance / 2, Pad->Mask, len + Pad->Mask, (Pad->Mask - Pad->Thickness) / 2, EMPTY (Pad->Name), EMPTY (element->Name[1].TextString), EMPTY (Pad->Number), TEST_FLAG (ONSOLDERFLAG, Pad) ? _("solder (bottom)") : _("component"), TEST_FLAG (LOCKFLAG, Pad) ? _("It is LOCKED.\n") : ""); break; } case ELEMENT_TYPE: { ElementType *element; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->element_tree->root, 0); return 0; } #endif element = (ElementType *) ptr2; pcb_snprintf (report, sizeof (report), _("%m+ELEMENT ID# %ld; Flags:%s\n" "BoundingBox %$mD %$mD.\n" "Descriptive Name \"%s\".\n" "Name on board \"%s\".\n" "Part number name \"%s\".\n" "It is %$mS tall and is located at (X,Y) = %$mD %s.\n" "Mark located at point (X,Y) = %$mD.\n" "It is on the %s side of the board.\n" "%s"), USER_UNITMASK, element->ID, flags_to_string (element->Flags, ELEMENT_TYPE), element->BoundingBox.X1, element->BoundingBox.Y1, element->BoundingBox.X2, element->BoundingBox.Y2, EMPTY (element->Name[0].TextString), EMPTY (element->Name[1].TextString), EMPTY (element->Name[2].TextString), SCALE_TEXT (FONT_CAPHEIGHT, element->Name[1].Scale), element->Name[1].X, element->Name[1].Y, TEST_FLAG (HIDENAMEFLAG, element) ? _(",\n but it's hidden") : "", element->MarkX, element->MarkY, TEST_FLAG (ONSOLDERFLAG, element) ? _("solder (bottom)") : _("component"), TEST_FLAG (LOCKFLAG, element) ? _("It is LOCKED.\n") : ""); break; } case TEXT_TYPE: #ifndef NDEBUG if (gui->shift_is_pressed ()) { LayerType *layer = (LayerType *) ptr1; __r_dump_tree (layer->text_tree->root, 0); return 0; } #endif case ELEMENTNAME_TYPE: { char laynum[32]; TextType *text; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->name_tree[NAME_INDEX (PCB)]->root, 0); return 0; } #endif text = (TextType *) ptr2; if (type == TEXT_TYPE) sprintf (laynum, _("It is on layer %d."), GetLayerNumber (PCB->Data, (LayerType *) ptr1)); pcb_snprintf (report, sizeof (report), _("%m+TEXT ID# %ld; Flags:%s\n" "Located at (X,Y) = %$mD.\n" "Characters are %$mS tall.\n" "Value is \"%s\".\n" "Direction is %d.\n" "The bounding box is %$mD %$mD.\n" "%s\n" "%s"), USER_UNITMASK, text->ID, flags_to_string (text->Flags, TEXT_TYPE), text->X, text->Y, SCALE_TEXT (FONT_CAPHEIGHT, text->Scale), text->TextString, text->Direction, text->BoundingBox.X1, text->BoundingBox.Y1, text->BoundingBox.X2, text->BoundingBox.Y2, (type == TEXT_TYPE) ? laynum : _("It is an element name."), TEST_FLAG (LOCKFLAG, text) ? _("It is LOCKED.\n") : ""); break; } case LINEPOINT_TYPE: case POLYGONPOINT_TYPE: { PointType *point = (PointType *) ptr2; pcb_snprintf (report, sizeof (report), _("%m+POINT ID# %ld.\n" "Located at (X,Y) = %$mD.\n" "It belongs to a %s on layer %d.\n"), USER_UNITMASK, point->ID, point->X, point->Y, (type == LINEPOINT_TYPE) ? C_("report", "line") : C_("report", "polygon"), GetLayerNumber (PCB->Data, (LayerType *) ptr1)); break; } case NO_TYPE: report[0] = '\0'; break; default: sprintf (report, _("Unknown\n")); break; } if (report[0] == '\0') { Message (_("Nothing found to report on\n")); return 1; } /* create dialog box */ gui->report_dialog (_("Report"), report); return 0; }
/* --------------------------------------------------------------------------- * draws the elements of a loaded circuit which is to be merged in */ static void XORDrawElement (ElementTypePtr Element, LocationType DX, LocationType DY) { /* if no silkscreen, draw the bounding box */ if (Element->ArcN == 0 && Element->LineN == 0) { gui->draw_line (Crosshair.GC, DX + Element->BoundingBox.X1, DY + Element->BoundingBox.Y1, DX + Element->BoundingBox.X1, DY + Element->BoundingBox.Y2); gui->draw_line (Crosshair.GC, DX + Element->BoundingBox.X1, DY + Element->BoundingBox.Y2, DX + Element->BoundingBox.X2, DY + Element->BoundingBox.Y2); gui->draw_line (Crosshair.GC, DX + Element->BoundingBox.X2, DY + Element->BoundingBox.Y2, DX + Element->BoundingBox.X2, DY + Element->BoundingBox.Y1); gui->draw_line (Crosshair.GC, DX + Element->BoundingBox.X2, DY + Element->BoundingBox.Y1, DX + Element->BoundingBox.X1, DY + Element->BoundingBox.Y1); } else { ELEMENTLINE_LOOP (Element); { gui->draw_line (Crosshair.GC, DX + line->Point1.X, DY + line->Point1.Y, DX + line->Point2.X, DY + line->Point2.Y); } END_LOOP; /* arc coordinates and angles have to be converted to X11 notation */ ARC_LOOP (Element); { gui->draw_arc (Crosshair.GC, DX + arc->X, DY + arc->Y, arc->Width, arc->Height, arc->StartAngle, arc->Delta); } END_LOOP; } /* pin coordinates and angles have to be converted to X11 notation */ PIN_LOOP (Element); { gui->draw_arc (Crosshair.GC, DX + pin->X, DY + pin->Y, pin->Thickness / 2, pin->Thickness / 2, 0, 360); } END_LOOP; /* pads */ PAD_LOOP (Element); { if ((TEST_FLAG (ONSOLDERFLAG, pad) != 0) == Settings.ShowSolderSide || PCB->InvisibleObjectsOn) { if (pad->Point1.X == pad->Point2.X || pad->Point1.Y == pad->Point2.Y) { int minx, miny, maxx, maxy; minx = DX + MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness/2; maxx = DX + MAX (pad->Point1.X, pad->Point2.X) + pad->Thickness/2; miny = DY + MIN (pad->Point1.Y, pad->Point2.Y) - pad->Thickness/2; maxy = DY + MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness/2; gui->draw_line (Crosshair.GC, minx, miny, maxx, miny); gui->draw_line (Crosshair.GC, minx, miny, minx, maxy); gui->draw_line (Crosshair.GC, maxx, miny, maxx, maxy); gui->draw_line (Crosshair.GC, minx, maxy, maxx, maxy); } else { /* FIXME: draw outlines, not centerlines. */ gui->draw_line (Crosshair.GC, DX + pad->Point1.X, DY + pad->Point1.Y, DX + pad->Point2.X, DY + pad->Point2.Y); } } } END_LOOP; /* mark */ gui->draw_line (Crosshair.GC, Element->MarkX + DX - EMARK_SIZE, Element->MarkY + DY, Element->MarkX + DX, Element->MarkY + DY - EMARK_SIZE); gui->draw_line (Crosshair.GC, Element->MarkX + DX + EMARK_SIZE, Element->MarkY + DY, Element->MarkX + DX, Element->MarkY + DY - EMARK_SIZE); gui->draw_line (Crosshair.GC, Element->MarkX + DX - EMARK_SIZE, Element->MarkY + DY, Element->MarkX + DX, Element->MarkY + DY + EMARK_SIZE); gui->draw_line (Crosshair.GC, Element->MarkX + DX + EMARK_SIZE, Element->MarkY + DY, Element->MarkX + DX, Element->MarkY + DY + EMARK_SIZE); }
/* --------------------------------------------------------------------------- * 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 ReportDialog (int argc, char **argv, int x, int y) { void *ptr1, *ptr2, *ptr3; int type, prec = Settings.grid_units_mm? 4: 2; char report[2048]; type = SearchScreen (x, y, REPORT_TYPES, &ptr1, &ptr2, &ptr3); if (type == NO_TYPE) type = SearchScreen (x, y, REPORT_TYPES | LOCKED_TYPE, &ptr1, &ptr2, &ptr3); switch (type) { case VIA_TYPE: { PinTypePtr via; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->via_tree->root, 0); return 0; } #endif via = (PinTypePtr) ptr2; if (TEST_FLAG (HOLEFLAG, via)) sprintf (&report[0], "VIA ID# %ld; Flags:%s\n" "(X,Y) = (%.*f, %.*f) %s.\n" "It is a pure hole of diameter %.*f %s.\n" "Name = \"%s\"." "%s", via->ID, flags_to_string (via->Flags, VIA_TYPE), prec, units (via->X), prec, UNIT (via->Y), prec, UNIT (via->DrillingHole), EMPTY (via->Name), TEST_FLAG (LOCKFLAG, via) ? "It is LOCKED.\n" : ""); else sprintf (&report[0], "VIA ID# %ld; Flags:%s\n" "(X,Y) = (%.*f, %.*f) %s.\n" "Copper width = %0.*f %s. Drill width = %0.*f %s.\n" "Clearance width in polygons = %0.*f %s.\n" "Annulus = %0.*f %s.\n" "Solder mask hole = %0.*f %s (gap = %0.*f %s).\n" "Name = \"%s\"." "%s", via->ID, flags_to_string (via->Flags, VIA_TYPE), prec, units (via->X), prec, UNIT (via->Y), prec, UNIT (via->Thickness), prec, UNIT (via->DrillingHole), prec, UNIT (via->Clearance / 2.), prec, UNIT ((via->Thickness - via->DrillingHole)/2), prec, UNIT (via->Mask), prec, UNIT ((via->Mask - via->Thickness)/2), EMPTY (via->Name), TEST_FLAG (LOCKFLAG, via) ? "It is LOCKED.\n" : ""); break; } case PIN_TYPE: { PinTypePtr Pin; ElementTypePtr element; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->pin_tree->root, 0); return 0; } #endif Pin = (PinTypePtr) ptr2; element = (ElementTypePtr) ptr1; PIN_LOOP (element); { if (pin == Pin) break; } END_LOOP; if (TEST_FLAG (HOLEFLAG, Pin)) sprintf (&report[0], "PIN ID# %ld; Flags:%s\n" "(X,Y) = (%.*f, %.*f) %s.\n" "It is a mounting hole. Drill width = %0.*f %s.\n" "It is owned by element %s.\n" "%s", Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE), prec, units (Pin->X), prec, UNIT (Pin->Y), prec, UNIT (Pin->DrillingHole), EMPTY (element->Name[1].TextString), TEST_FLAG (LOCKFLAG, Pin) ? "It is LOCKED.\n" : ""); else sprintf (&report[0], "PIN ID# %ld; Flags:%s\n" "(X,Y) = (%.*f, %.*f) %s.\n" "Copper width = %0.*f %s. Drill width = %0.*f %s.\n" "Clearance width to Polygon = %0.*f %s.\n" "Annulus = %0.*f %s.\n" "Solder mask hole = %0.*f %s (gap = %0.*f %s).\n" "Name = \"%s\".\n" "It is owned by element %s\n as pin number %s.\n" "%s", Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE), prec, units(Pin->X), prec, UNIT(Pin->Y), prec, UNIT (Pin->Thickness), prec, UNIT (Pin->DrillingHole), prec, UNIT (Pin->Clearance / 2.), prec, UNIT ((Pin->Thickness - Pin->DrillingHole)/2), prec, UNIT (Pin->Mask), prec, UNIT ((Pin->Mask - Pin->Thickness)/2), EMPTY (Pin->Name), EMPTY (element->Name[1].TextString), EMPTY (Pin->Number), TEST_FLAG (LOCKFLAG, Pin) ? "It is LOCKED.\n" : ""); break; } case LINE_TYPE: { LineTypePtr line; #ifndef NDEBUG if (gui->shift_is_pressed ()) { LayerTypePtr layer = (LayerTypePtr) ptr1; __r_dump_tree (layer->line_tree->root, 0); return 0; } #endif line = (LineTypePtr) ptr2; sprintf (&report[0], "LINE ID# %ld; Flags:%s\n" "FirstPoint(X,Y) = (%.*f, %.*f) %s, ID = %ld.\n" "SecondPoint(X,Y) = (%.*f, %.*f) %s, ID = %ld.\n" "Width = %0.*f %s.\nClearance width in polygons = %0.*f %s.\n" "It is on layer %d\n" "and has name \"%s\".\n" "%s", line->ID, flags_to_string (line->Flags, LINE_TYPE), prec, units (line->Point1.X), prec, UNIT (line->Point1.Y), line->Point1.ID, prec, units (line->Point2.X), prec, UNIT (line->Point2.Y), line->Point2.ID, prec, UNIT (line->Thickness), prec, UNIT (line->Clearance / 2.), GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1), UNKNOWN (line->Number), TEST_FLAG (LOCKFLAG, line) ? "It is LOCKED.\n" : ""); break; } case RATLINE_TYPE: { RatTypePtr line; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->rat_tree->root, 0); return 0; } #endif line = (RatTypePtr) ptr2; sprintf (&report[0], "RAT-LINE ID# %ld; Flags:%s\n" "FirstPoint(X,Y) = (%.*f, %.*f) %s; ID = %ld; " "connects to layer group %d.\n" "SecondPoint(X,Y) = (%.*f, %.*f) %s; ID = %ld; " "connects to layer group %d.\n", line->ID, flags_to_string (line->Flags, LINE_TYPE), prec, units (line->Point1.X), prec, UNIT (line->Point1.Y), line->Point1.ID, line->group1, prec, units (line->Point2.X), prec, UNIT (line->Point2.Y), line->Point2.ID, line->group2); break; } case ARC_TYPE: { ArcTypePtr Arc; BoxTypePtr box; #ifndef NDEBUG if (gui->shift_is_pressed ()) { LayerTypePtr layer = (LayerTypePtr) ptr1; __r_dump_tree (layer->arc_tree->root, 0); return 0; } #endif Arc = (ArcTypePtr) ptr2; box = GetArcEnds (Arc); sprintf (&report[0], "ARC ID# %ld; Flags:%s\n" "CenterPoint(X,Y) = (%.*f, %.*f) %s.\n" "Radius = %0.*f %s, Thickness = %0.*f %s.\n" "Clearance width in polygons = %0.*f %s.\n" "StartAngle = %ld degrees, DeltaAngle = %ld degrees.\n" "Bounding Box is (%.*f,%.*f), (%.*f,%.*f) %s.\n" "That makes the end points at (%.*f,%.*f) %s and (%.*f,%.*f) %s.\n" "It is on layer %d.\n" "%s", Arc->ID, flags_to_string (Arc->Flags, ARC_TYPE), prec, units(Arc->X), prec, UNIT(Arc->Y), prec, UNIT (Arc->Width), prec, UNIT (Arc->Thickness), prec, UNIT (Arc->Clearance / 2.), Arc->StartAngle, Arc->Delta, prec, units (Arc->BoundingBox.X1), prec, units (Arc->BoundingBox.Y1), prec, units (Arc->BoundingBox.X2), prec, UNIT (Arc->BoundingBox.Y2), prec, units (box->X1), prec, UNIT (box->Y1), prec, units (box->X2), prec, UNIT (box->Y2), GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1), TEST_FLAG (LOCKFLAG, Arc) ? "It is LOCKED.\n" : ""); break; } case POLYGON_TYPE: { PolygonTypePtr Polygon; #ifndef NDEBUG if (gui->shift_is_pressed ()) { LayerTypePtr layer = (LayerTypePtr) ptr1; __r_dump_tree (layer->polygon_tree->root, 0); return 0; } #endif Polygon = (PolygonTypePtr) ptr2; sprintf (&report[0], "POLYGON ID# %ld; Flags:%s\n" "Its bounding box is (%.*f,%.*f) (%.*f,%.*f) %s.\n" "It has %d points and could store %d more\n" " without using more memory.\n" "It has %d holes and resides on layer %d.\n" "%s", Polygon->ID, flags_to_string (Polygon->Flags, POLYGON_TYPE), prec, units(Polygon->BoundingBox.X1), prec, units(Polygon->BoundingBox.Y1), prec, units(Polygon->BoundingBox.X2), prec, UNIT(Polygon->BoundingBox.Y2), Polygon->PointN, Polygon->PointMax - Polygon->PointN, Polygon->HoleIndexN, GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1), TEST_FLAG (LOCKFLAG, Polygon) ? "It is LOCKED.\n" : ""); break; } case PAD_TYPE: { int len, dx, dy, mgap; PadTypePtr Pad; ElementTypePtr element; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->pad_tree->root, 0); return 0; } #endif Pad = (PadTypePtr) ptr2; element = (ElementTypePtr) ptr1; PAD_LOOP (element); { { if (pad == Pad) break; } } END_LOOP; dx = Pad->Point1.X - Pad->Point2.X; dy = Pad->Point1.Y - Pad->Point2.Y; len = sqrt (dx*dx+dy*dy); mgap = (Pad->Mask - Pad->Thickness)/2; sprintf (&report[0], "PAD ID# %ld; Flags:%s\n" "FirstPoint(X,Y) = (%.*f, %.*f) %s; ID = %ld.\n" "SecondPoint(X,Y) = (%.*f, %.*f) %s; ID = %ld.\n" "Width = %0.*f %s. Length = %0.*f %s.\n" "Clearance width in polygons = %0.*f %s.\n" "Solder mask = %0.*f x %0.*f %s (gap = %0.*f %s).\n" "Name = \"%s\".\n" "It is owned by SMD element %s\n" " as pin number %s and is on the %s\n" "side of the board.\n" "%s", Pad->ID, flags_to_string (Pad->Flags, PAD_TYPE), prec, units (Pad->Point1.X), prec, UNIT (Pad->Point1.Y), Pad->Point1.ID, prec, units (Pad->Point2.X), prec, UNIT (Pad->Point2.Y), Pad->Point2.ID, prec, UNIT (Pad->Thickness), prec, UNIT (len + Pad->Thickness), prec, UNIT (Pad->Clearance / 2.), prec, units (Pad->Mask), prec, UNIT (Pad->Mask + len), prec, UNIT (mgap), EMPTY (Pad->Name), EMPTY (element->Name[1].TextString), EMPTY (Pad->Number), TEST_FLAG (ONSOLDERFLAG, Pad) ? "solder (bottom)" : "component", TEST_FLAG (LOCKFLAG, Pad) ? "It is LOCKED.\n" : ""); break; } case ELEMENT_TYPE: { ElementTypePtr element; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->element_tree->root, 0); return 0; } #endif element = (ElementTypePtr) ptr2; sprintf (&report[0], "ELEMENT ID# %ld; Flags:%s\n" "BoundingBox (%.*f,%.*f) (%.*f,%.*f) %s.\n" "Descriptive Name \"%s\".\n" "Name on board \"%s\".\n" "Part number name \"%s\".\n" "It is %.*f %s tall and is located at (X,Y) = (%.*f,%.*f)%s.\n" "Mark located at point (X,Y) = (%.*f,%.*f).\n" "It is on the %s side of the board.\n" "%s", element->ID, flags_to_string (element->Flags, ELEMENT_TYPE), prec, units(element->BoundingBox.X1), prec, units (element->BoundingBox.Y1), prec, units(element->BoundingBox.X2), prec, UNIT (element->BoundingBox.Y2), EMPTY (element->Name[0].TextString), EMPTY (element->Name[1].TextString), EMPTY (element->Name[2].TextString), prec, UNIT (0.45 * element->Name[1].Scale * 100.), prec, units(element->Name[1].X), prec, units(element->Name[1].Y), TEST_FLAG (HIDENAMEFLAG, element) ? ",\n but it's hidden" : "", prec, units(element->MarkX), prec, units(element->MarkY), TEST_FLAG (ONSOLDERFLAG, element) ? "solder (bottom)" : "component", TEST_FLAG (LOCKFLAG, element) ? "It is LOCKED.\n" : ""); break; } case TEXT_TYPE: #ifndef NDEBUG if (gui->shift_is_pressed ()) { LayerTypePtr layer = (LayerTypePtr) ptr1; __r_dump_tree (layer->text_tree->root, 0); return 0; } #endif case ELEMENTNAME_TYPE: { char laynum[32]; TextTypePtr text; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->name_tree[NAME_INDEX (PCB)]->root, 0); return 0; } #endif text = (TextTypePtr) ptr2; if (type == TEXT_TYPE) sprintf (laynum, "It is on layer %d.", GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1)); sprintf (&report[0], "TEXT ID# %ld; Flags:%s\n" "Located at (X,Y) = (%.*f,%.*f) %s.\n" "Characters are %0.*f %s tall.\n" "Value is \"%s\".\n" "Direction is %d.\n" "The bounding box is (%.*f,%.*f) (%.*f, %.*f) %s.\n" "%s\n" "%s", text->ID, flags_to_string (text->Flags, TEXT_TYPE), prec, units(text->X), prec, UNIT (text->Y), prec, UNIT (0.45 * text->Scale * 100.), text->TextString, text->Direction, prec, units(text->BoundingBox.X1), prec, units(text->BoundingBox.Y1), prec, units(text->BoundingBox.X2), prec, UNIT (text->BoundingBox.Y2), (type == TEXT_TYPE) ? laynum : "It is an element name.", TEST_FLAG (LOCKFLAG, text) ? "It is LOCKED.\n" : ""); break; } case LINEPOINT_TYPE: case POLYGONPOINT_TYPE: { PointTypePtr point = (PointTypePtr) ptr2; sprintf (&report[0], "POINT ID# %ld.\n" "Located at (X,Y) = (%.*f,%.*f) %s.\n" "It belongs to a %s on layer %d.\n", point->ID, prec, units (point->X), prec, UNIT (point->Y), (type == LINEPOINT_TYPE) ? "line" : "polygon", GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1)); break; } case NO_TYPE: report[0] = '\0'; break; default: sprintf (&report[0], "Unknown\n"); break; } if (report[0] == '\0') { Message (_("Nothing found to report on\n")); return 1; } HideCrosshair (false); /* create dialog box */ gui->report_dialog ("Report", &report[0]); RestoreCrosshair (false); return 0; }
/* --------------------------------------------------------------------------- * copies data from one element to another and creates the destination * if necessary */ ElementType * CopyElementLowLevel (DataType *Data, ElementType *Src, bool uniqueName, Coord dx, Coord dy, int mask_flags) { int i; ElementType *Dest; /* both coordinates and flags are the same */ Dest = CreateNewElement (Data, &PCB->Font, MaskFlags (Src->Flags, mask_flags), DESCRIPTION_NAME (Src), NAMEONPCB_NAME (Src), VALUE_NAME (Src), DESCRIPTION_TEXT (Src).X + dx, DESCRIPTION_TEXT (Src).Y + dy, DESCRIPTION_TEXT (Src).Direction, DESCRIPTION_TEXT (Src).Scale, MaskFlags (DESCRIPTION_TEXT (Src).Flags, mask_flags), uniqueName); /* abort on error */ if (!Dest) return (Dest); ELEMENTLINE_LOOP (Src); { CreateNewLineInElement (Dest, line->Point1.X + dx, line->Point1.Y + dy, line->Point2.X + dx, line->Point2.Y + dy, line->Thickness); } END_LOOP; PIN_LOOP (Src); { CreateNewPin (Dest, pin->X + dx, pin->Y + dy, pin->Thickness, pin->Clearance, pin->Mask, pin->DrillingHole, pin->Name, pin->Number, MaskFlags (pin->Flags, mask_flags)); } END_LOOP; PAD_LOOP (Src); { CreateNewPad (Dest, pad->Point1.X + dx, pad->Point1.Y + dy, pad->Point2.X + dx, pad->Point2.Y + dy, pad->Thickness, pad->Clearance, pad->Mask, pad->Name, pad->Number, MaskFlags (pad->Flags, mask_flags)); } END_LOOP; ARC_LOOP (Src); { CreateNewArcInElement (Dest, arc->X + dx, arc->Y + dy, arc->Width, arc->Height, arc->StartAngle, arc->Delta, arc->Thickness); } END_LOOP; for (i=0; i<Src->Attributes.Number; i++) CreateNewAttribute (& Dest->Attributes, Src->Attributes.List[i].name, Src->Attributes.List[i].value); Dest->MarkX = Src->MarkX + dx; Dest->MarkY = Src->MarkY + dy; SetElementBoundingBox (Data, Dest, &PCB->Font); return (Dest); }
static int PrintBOM (void) { char utcTime[64]; Coord x, y; double theta = 0.0; double sumx, sumy; int pinfound[MAXREFPINS]; double pinx[MAXREFPINS]; double piny[MAXREFPINS]; double pinangle[MAXREFPINS]; double padcentrex, padcentrey; double centroidx, centroidy; double pin1x, pin1y; int pin_cnt; int found_any_not_at_centroid; int found_any; time_t currenttime; FILE *fp; BomList *bom = NULL; char *name, *descr, *value,*fixed_rotation; int rpindex; fp = fopen (xy_filename, "w"); if (!fp) { gui->log ("Cannot open file %s for writing\n", xy_filename); return 1; } /* Create a portable timestamp. */ currenttime = time (NULL); { /* avoid gcc complaints */ const char *fmt = "%c UTC"; strftime (utcTime, sizeof (utcTime), fmt, gmtime (¤ttime)); } fprintf (fp, "# PcbXY Version 1.0\n"); fprintf (fp, "# Date: %s\n", utcTime); fprintf (fp, "# Author: %s\n", pcb_author ()); fprintf (fp, "# Title: %s - PCB X-Y\n", UNKNOWN (PCB->Name)); fprintf (fp, "# RefDes, Description, Value, X, Y, rotation, top/bottom\n"); /* don't use localized xy_unit->in_suffix here since */ /* the line itself is not localized and not for GUI */ fprintf (fp, "# X,Y in %s. rotation in degrees.\n", xy_unit->suffix); fprintf (fp, "# --------------------------------------------\n"); /* * For each element we calculate the centroid of the footprint. * In addition, we need to extract some notion of rotation. * While here generate the BOM list */ ELEMENT_LOOP (PCB->Data); { /* Initialize our pin count and our totals for finding the centroid. */ pin_cnt = 0; sumx = 0.0; sumy = 0.0; for (rpindex = 0; rpindex < MAXREFPINS; rpindex++) pinfound[rpindex] = 0; /* Insert this component into the bill of materials list. */ bom = bom_insert ((char *)UNKNOWN (NAMEONPCB_NAME (element)), (char *)UNKNOWN (DESCRIPTION_NAME (element)), (char *)UNKNOWN (VALUE_NAME (element)), bom); /* * Iterate over the pins and pads keeping a running count of how * many pins/pads total and the sum of x and y coordinates * * While we're at it, store the location of pin/pad #1 and #2 if * we can find them. */ PIN_LOOP (element); { sumx += (double) pin->X; sumy += (double) pin->Y; pin_cnt++; for (rpindex = 0; reference_pin_names[rpindex]; rpindex++) { if (NSTRCMP (pin->Number, reference_pin_names[rpindex]) == 0) { pinx[rpindex] = (double) pin->X; piny[rpindex] = (double) pin->Y; pinangle[rpindex] = 0.0; /* pins have no notion of angle */ pinfound[rpindex] = 1; } } } END_LOOP; PAD_LOOP (element); { sumx += (pad->Point1.X + pad->Point2.X) / 2.0; sumy += (pad->Point1.Y + pad->Point2.Y) / 2.0; pin_cnt++; for (rpindex = 0; reference_pin_names[rpindex]; rpindex++) { if (NSTRCMP (pad->Number, reference_pin_names[rpindex]) == 0) { padcentrex = (double) (pad->Point1.X + pad->Point2.X) / 2.0; padcentrey = (double) (pad->Point1.Y + pad->Point2.Y) / 2.0; pinx[rpindex] = padcentrex; piny[rpindex] = padcentrey; /* * NOTE: We swap the Y points because in PCB, the Y-axis * is inverted. Increasing Y moves down. We want to deal * in the usual increasing Y moves up coordinates though. */ pinangle[rpindex] = (180.0 / M_PI) * atan2 (pad->Point1.Y - pad->Point2.Y, pad->Point2.X - pad->Point1.X); pinfound[rpindex]=1; } } } END_LOOP; if (pin_cnt > 0) { centroidx = sumx / (double) pin_cnt; centroidy = sumy / (double) pin_cnt; if (NSTRCMP( AttributeGetFromList (&element->Attributes,"xy-centre"), "origin") == 0 ) { x = element->MarkX; y = element->MarkY; } else { x = centroidx; y = centroidy; } fixed_rotation = AttributeGetFromList (&element->Attributes, "xy-fixed-rotation"); if (fixed_rotation) { /* The user specified a fixed rotation */ theta = atof (fixed_rotation); found_any_not_at_centroid = 1; found_any = 1; } else { /* Find first reference pin not at the centroid */ found_any_not_at_centroid = 0; found_any = 0; theta = 0.0; for (rpindex = 0; reference_pin_names[rpindex] && !found_any_not_at_centroid; rpindex++) { if (pinfound[rpindex]) { found_any = 1; /* Recenter pin "#1" onto the axis which cross at the part centroid */ pin1x = pinx[rpindex] - x; pin1y = piny[rpindex] - y; /* flip x, to reverse rotation for elements on back */ if (FRONT (element) != 1) pin1x = -pin1x; /* if only 1 pin, use pin 1's angle */ if (pin_cnt == 1) { theta = pinangle[rpindex]; found_any_not_at_centroid = 1; } else if ((pin1x != 0.0) || (pin1y != 0.0)) { theta = xyToAngle (pin1x, pin1y, pin_cnt > 2); found_any_not_at_centroid = 1; } } } if (!found_any) { Message ("PrintBOM(): unable to figure out angle because I could\n" " not find a suitable reference pin of element %s\n" " Setting to %g degrees\n", UNKNOWN (NAMEONPCB_NAME (element)), theta); } else if (!found_any_not_at_centroid) { Message ("PrintBOM(): unable to figure out angle of element\n" " %s because the reference pin(s) are at the centroid of the part.\n" " Setting to %g degrees\n", UNKNOWN (NAMEONPCB_NAME (element)), theta); } } name = CleanBOMString ((char *)UNKNOWN (NAMEONPCB_NAME (element))); descr = CleanBOMString ((char *)UNKNOWN (DESCRIPTION_NAME (element))); value = CleanBOMString ((char *)UNKNOWN (VALUE_NAME (element))); y = PCB->MaxHeight - y; pcb_fprintf (fp, "%m+%s,\"%s\",\"%s\",%.2mS,%.2mS,%g,%s\n", xy_unit->allow, name, descr, value, x, y, theta, FRONT (element) == 1 ? "top" : "bottom"); free (name); free (descr); free (value); } } END_LOOP; fclose (fp); /* Now print out a Bill of Materials file */ fp = fopen (bom_filename, "w"); if (!fp) { gui->log ("Cannot open file %s for writing\n", bom_filename); print_and_free (NULL, bom); return 1; } fprintf (fp, "# PcbBOM Version 1.0\n"); fprintf (fp, "# Date: %s\n", utcTime); fprintf (fp, "# Author: %s\n", pcb_author ()); fprintf (fp, "# Title: %s - PCB BOM\n", UNKNOWN (PCB->Name)); fprintf (fp, "# Quantity, Description, Value, RefDes\n"); fprintf (fp, "# --------------------------------------------\n"); print_and_free (fp, bom); fclose (fp); return (0); }
static void pinout_set_data (GhidPinoutPreview * pinout, ElementType * element) { gint tx, ty, x_min = 0, y_min = 0; if (element == NULL) { FreeElementMemory (&pinout->element); pinout->w_pixels = 0; pinout->h_pixels = 0; return; } /* * copy element data * enable output of pin and padnames * move element to a 5% offset from zero position * set all package lines/arcs to zero width */ CopyElementLowLevel (NULL, &pinout->element, element, FALSE, 0, 0); PIN_LOOP (&pinout->element); { tx = abs (pinout->element.Pin[0].X - pin->X); ty = abs (pinout->element.Pin[0].Y - pin->Y); if (x_min == 0 || (tx != 0 && tx < x_min)) x_min = tx; if (y_min == 0 || (ty != 0 && ty < y_min)) y_min = ty; SET_FLAG (DISPLAYNAMEFLAG, pin); } END_LOOP; PAD_LOOP (&pinout->element); { tx = abs (pinout->element.Pad[0].Point1.X - pad->Point1.X); ty = abs (pinout->element.Pad[0].Point1.Y - pad->Point1.Y); if (x_min == 0 || (tx != 0 && tx < x_min)) x_min = tx; if (y_min == 0 || (ty != 0 && ty < y_min)) y_min = ty; SET_FLAG (DISPLAYNAMEFLAG, pad); } END_LOOP; MoveElementLowLevel (NULL, &pinout->element, Settings.PinoutOffsetX - pinout->element.BoundingBox.X1, Settings.PinoutOffsetY - pinout->element.BoundingBox.Y1); if (!pinout_zoom_fit (pinout, 2)) pinout_zoom_fit (pinout, 3); ELEMENTLINE_LOOP (&pinout->element); { line->Thickness = 0; } END_LOOP; ARC_LOOP (&pinout->element); { /* * for whatever reason setting a thickness of 0 causes the arcs to * not display so pick 1 which does display but is still quite * thin. */ arc->Thickness = 1; } END_LOOP; }
/* --------------------------------------------------------------------------- * 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); }
/* --------------------------------------------------------------------------- * moves a element by +-X and +-Y */ void MoveElementLowLevel (DataTypePtr Data, ElementTypePtr Element, Coord DX, Coord DY) { if (Data) r_delete_entry (Data->element_tree, (BoxType *)Element); ELEMENTLINE_LOOP (Element); { MOVE_LINE_LOWLEVEL (line, DX, DY); } END_LOOP; PIN_LOOP (Element); { if (Data) { r_delete_entry (Data->pin_tree, (BoxType *)pin); RestoreToPolygon (Data, PIN_TYPE, Element, pin); } MOVE_PIN_LOWLEVEL (pin, DX, DY); if (Data) { r_insert_entry (Data->pin_tree, (BoxType *)pin, 0); ClearFromPolygon (Data, PIN_TYPE, Element, pin); } } END_LOOP; PAD_LOOP (Element); { if (Data) { r_delete_entry (Data->pad_tree, (BoxType *)pad); RestoreToPolygon (Data, PAD_TYPE, Element, pad); } MOVE_PAD_LOWLEVEL (pad, DX, DY); if (Data) { r_insert_entry (Data->pad_tree, (BoxType *)pad, 0); ClearFromPolygon (Data, PAD_TYPE, Element, pad); } } END_LOOP; ARC_LOOP (Element); { MOVE_ARC_LOWLEVEL (arc, DX, DY); } END_LOOP; ELEMENTTEXT_LOOP (Element); { if (Data && Data->name_tree[n]) r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text); MOVE_TEXT_LOWLEVEL (text, DX, DY); if (Data && Data->name_tree[n]) r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0); } END_LOOP; MOVE_BOX_LOWLEVEL (&Element->BoundingBox, DX, DY); MOVE_BOX_LOWLEVEL (&Element->VBox, DX, DY); MOVE (Element->MarkX, Element->MarkY, DX, DY); if (Data) r_insert_entry (Data->element_tree, (BoxType *)Element, 0); }
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; }