/* --------------------------------------------------------------------------- * creates a new line for an element */ LineTypePtr CreateNewLineInElement (ElementTypePtr Element, LocationType X1, LocationType Y1, LocationType X2, LocationType Y2, BDimension Thickness) { LineTypePtr line = Element->Line; if (Thickness == 0) return (NULL); /* realloc new memory if necessary and clear it */ if (Element->LineN >= Element->LineMax) { Element->LineMax += STEP_ELEMENTLINE; line = (LineTypePtr)realloc (line, Element->LineMax * sizeof (LineType)); Element->Line = line; memset (line + Element->LineN, 0, STEP_ELEMENTLINE * sizeof (LineType)); } /* copy values */ line = line + Element->LineN++; line->Point1.X = X1; line->Point1.Y = Y1; line->Point2.X = X2; line->Point2.Y = Y2; line->Thickness = Thickness; line->Flags = NoFlags (); line->ID = ID++; return (line); }
/*! * \brief Creates a new line for an element. */ LineType * CreateNewLineInElement (ElementType *Element, Coord X1, Coord Y1, Coord X2, Coord Y2, Coord Thickness) { LineType *line; if (Thickness == 0) return NULL; line = g_slice_new0 (LineType); Element->Line = g_list_append (Element->Line, line); Element->LineN ++; /* copy values */ line->Point1.X = X1; line->Point1.Y = Y1; line->Point2.X = X2; line->Point2.Y = Y2; line->Thickness = Thickness; line->Flags = NoFlags (); line->ID = ID++; return line; }
/*! * \brief Creates a new line on a layer and checks for overlap and * extension. */ LineType * CreateDrawnLineOnLayer (LayerType *Layer, Coord X1, Coord Y1, Coord X2, Coord Y2, Coord Thickness, Coord Clearance, FlagType Flags) { struct line_info info; BoxType search; search.X1 = MIN (X1, X2); search.X2 = MAX (X1, X2); search.Y1 = MIN (Y1, Y2); search.Y2 = MAX (Y1, Y2); if (search.Y2 == search.Y1) search.Y2++; if (search.X2 == search.X1) search.X2++; info.X1 = X1; info.X2 = X2; info.Y1 = Y1; info.Y2 = Y2; info.Thickness = Thickness; info.Clearance = Clearance; info.Flags = Flags; info.test.Thickness = 0; info.test.Flags = NoFlags (); info.ans = NULL; /* prevent stacking of duplicate lines * and remove needless intermediate points * verify that the layer is on the board first! */ if (setjmp (info.env) == 0) { r_search (Layer->line_tree, &search, NULL, line_callback, &info); return CreateNewLineOnLayer (Layer, X1, Y1, X2, Y2, Thickness, Clearance, Flags); } if ((void *) info.ans == (void *) (-1)) return NULL; /* stacked line */ /* remove unnecessary points */ if (info.ans) { /* must do this BEFORE getting new line memory */ MoveObjectToRemoveUndoList (LINE_TYPE, Layer, info.ans, info.ans); X1 = info.test.Point1.X; X2 = info.test.Point2.X; Y1 = info.test.Point1.Y; Y2 = info.test.Point2.Y; } return CreateNewLineOnLayer (Layer, X1, Y1, X2, Y2, Thickness, Clearance, Flags); }
/* --------------------------------------------------------------------------- * copies a polygon */ static void * CopyPolygon (LayerType *Layer, PolygonType *Polygon) { PolygonType *polygon; polygon = CreateNewPolygon (Layer, NoFlags ()); CopyPolygonLowLevel (polygon, Polygon); MovePolygonLowLevel (polygon, DeltaX, DeltaY); if (!Layer->polygon_tree) Layer->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->polygon_tree, (BoxType *) polygon, 0); InitClip (PCB->Data, Layer, polygon); DrawPolygon (Layer, polygon); AddObjectToCreateUndoList (POLYGON_TYPE, Layer, polygon, polygon); return (polygon); }
static int moveline_callback (const BoxType * b, void *cl) { struct via_info *i = (struct via_info *) cl; PinTypePtr via; if ((via = CreateNewVia (PCB->Data, i->X, i->Y, Settings.ViaThickness, 2 * Settings.Keepaway, NOFLAG, Settings.ViaDrillingHole, NULL, NoFlags ())) != NULL) { AddObjectToCreateUndoList (VIA_TYPE, via, via, via); DrawVia (via); } longjmp (i->env, 1); }
/* --------------------------------------------------------------------------- * checks if a line crosses a rectangle */ bool IsLineInRectangle (Coord X1, Coord Y1, Coord X2, Coord Y2, LineTypePtr Line) { LineType line; /* first, see if point 1 is inside the rectangle */ /* in case the whole line is inside the rectangle */ if (X1 < Line->Point1.X && X2 > Line->Point1.X && Y1 < Line->Point1.Y && Y2 > Line->Point1.Y) return (true); /* construct a set of dummy lines and check each of them */ line.Thickness = 0; line.Flags = NoFlags (); /* upper-left to upper-right corner */ line.Point1.Y = line.Point2.Y = Y1; line.Point1.X = X1; line.Point2.X = X2; if (LineLineIntersect (&line, Line)) return (true); /* upper-right to lower-right corner */ line.Point1.X = X2; line.Point1.Y = Y1; line.Point2.Y = Y2; if (LineLineIntersect (&line, Line)) return (true); /* lower-right to lower-left corner */ line.Point1.Y = Y2; line.Point1.X = X1; line.Point2.X = X2; if (LineLineIntersect (&line, Line)) return (true); /* lower-left to upper-left corner */ line.Point2.X = X1; line.Point1.Y = Y1; line.Point2.Y = Y2; if (LineLineIntersect (&line, Line)) return (true); return (false); }
static void draw_pad_name (PadType *pad) { BoxType box; bool vert; TextType text; if (!pad->Name || !pad->Name[0]) text.TextString = EMPTY (pad->Number); else text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pad->Number : pad->Name); /* should text be vertical ? */ vert = (pad->Point1.X == pad->Point2.X); if (vert) { box.X1 = pad->Point1.X - pad->Thickness / 2; box.Y1 = MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness / 2; box.X1 += Settings.PinoutTextOffsetY; box.Y1 -= Settings.PinoutTextOffsetX; } else { box.X1 = MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness / 2; box.Y1 = pad->Point1.Y - pad->Thickness / 2; box.X1 += Settings.PinoutTextOffsetX; box.Y1 += Settings.PinoutTextOffsetY; } gui->graphics->set_color (Output.fgGC, PCB->PinNameColor); text.Flags = NoFlags (); /* Set font height to approx 90% of pin thickness */ text.Scale = 90 * pad->Thickness / FONT_CAPHEIGHT; text.X = box.X1; text.Y = box.Y1; text.Direction = vert ? 1 : 0; gui->graphics->draw_pcb_text (Output.fgGC, &text, 0); }
static void _draw_pv_name (PinType *pv) { BoxType box; bool vert; TextType text; if (!pv->Name || !pv->Name[0]) text.TextString = EMPTY (pv->Number); else text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pv->Number : pv->Name); vert = TEST_FLAG (EDGE2FLAG, pv); if (vert) { box.X1 = pv->X - pv->Thickness / 2 + Settings.PinoutTextOffsetY; box.Y1 = pv->Y - pv->DrillingHole / 2 - Settings.PinoutTextOffsetX; } else { box.X1 = pv->X + pv->DrillingHole / 2 + Settings.PinoutTextOffsetX; box.Y1 = pv->Y - pv->Thickness / 2 + Settings.PinoutTextOffsetY; } gui->graphics->set_color (Output.fgGC, PCB->PinNameColor); text.Flags = NoFlags (); /* Set font height to approx 56% of pin thickness */ text.Scale = 56 * pv->Thickness / FONT_CAPHEIGHT; text.X = box.X1; text.Y = box.Y1; text.Direction = vert ? 1 : 0; if (gui->gui) doing_pinout++; gui->graphics->draw_pcb_text (Output.fgGC, &text, 0); if (gui->gui) doing_pinout--; }
/* --------------------------------------------------------------------------- * checks if an arc crosses a square */ bool IsArcInRectangle (Coord X1, Coord Y1, Coord X2, Coord Y2, ArcTypePtr Arc) { LineType line; /* construct a set of dummy lines and check each of them */ line.Thickness = 0; line.Flags = NoFlags (); /* upper-left to upper-right corner */ line.Point1.Y = line.Point2.Y = Y1; line.Point1.X = X1; line.Point2.X = X2; if (LineArcIntersect (&line, Arc)) return (true); /* upper-right to lower-right corner */ line.Point1.X = line.Point2.X = X2; line.Point1.Y = Y1; line.Point2.Y = Y2; if (LineArcIntersect (&line, Arc)) return (true); /* lower-right to lower-left corner */ line.Point1.Y = line.Point2.Y = Y2; line.Point1.X = X1; line.Point2.X = X2; if (LineArcIntersect (&line, Arc)) return (true); /* lower-left to upper-left corner */ line.Point1.X = line.Point2.X = X1; line.Point1.Y = Y1; line.Point2.Y = Y2; if (LineArcIntersect (&line, Arc)) return (true); return (false); }
/* --------------------------------------------------------------------------- * checks if a line crosses a quadrangle: almost copied from IsLineInRectangle() * Note: actually this quadrangle is a slanted rectangle */ bool IsLineInQuadrangle (PointType p[4], LineTypePtr Line) { LineType line; /* first, see if point 1 is inside the rectangle */ /* in case the whole line is inside the rectangle */ if (IsPointInQuadrangle(p,&(Line->Point1))) return true; if (IsPointInQuadrangle(p,&(Line->Point2))) return true; /* construct a set of dummy lines and check each of them */ line.Thickness = 0; line.Flags = NoFlags (); /* upper-left to upper-right corner */ line.Point1.X = p[0].X; line.Point1.Y = p[0].Y; line.Point2.X = p[1].X; line.Point2.Y = p[1].Y; if (LineLineIntersect (&line, Line)) return (true); /* upper-right to lower-right corner */ line.Point1.X = p[2].X; line.Point1.Y = p[2].Y; if (LineLineIntersect (&line, Line)) return (true); /* lower-right to lower-left corner */ line.Point2.X = p[3].X; line.Point2.Y = p[3].Y; if (LineLineIntersect (&line, Line)) return (true); /* lower-left to upper-left corner */ line.Point1.X = p[0].X; line.Point1.Y = p[0].Y; if (LineLineIntersect (&line, Line)) return (true); return (false); }
static int FontEdit (int argc, char **argv, int Ux, int Uy) { FontType *font; SymbolType *symbol; LayerTypePtr lfont, lorig, lwidth, lgrid; int s, l; if (hid_actionl ("New", "Font", 0)) return 1; while (PCB->Data->LayerN > 4) MoveLayer (4, -1); for (l = 0; l < 4; l++) { MoveLayerToGroup (l, l); } PCB->MaxWidth = CELL_SIZE * 18; PCB->MaxHeight = CELL_SIZE * ((MAX_FONTPOSITION + 15) / 16 + 2); PCB->Grid = 500.0; PCB->Data->Layer[0].Name = MyStrdup ("Font", "FontEdit"); PCB->Data->Layer[1].Name = MyStrdup ("OrigFont", "FontEdit"); PCB->Data->Layer[2].Name = MyStrdup ("Width", "FontEdit"); PCB->Data->Layer[3].Name = MyStrdup ("Grid", "FontEdit"); hid_action ("PCBChanged"); hid_action ("LayersChanged"); lfont = PCB->Data->Layer + 0; lorig = PCB->Data->Layer + 1; lwidth = PCB->Data->Layer + 2; lgrid = PCB->Data->Layer + 3; font = &PCB->Font; for (s = 0; s <= MAX_FONTPOSITION; s++) { int ox = (s % 16 + 1) * CELL_SIZE; int oy = (s / 16 + 1) * CELL_SIZE; int w, miny, maxy, maxx = 0; symbol = &font->Symbol[s]; miny = 500; maxy = font->MaxHeight; for (l = 0; l < symbol->LineN; l++) { CreateDrawnLineOnLayer (lfont, symbol->Line[l].Point1.X + ox, symbol->Line[l].Point1.Y + oy, symbol->Line[l].Point2.X + ox, symbol->Line[l].Point2.Y + oy, symbol->Line[l].Thickness, symbol->Line[l].Thickness, NoFlags ()); CreateDrawnLineOnLayer (lorig, symbol->Line[l].Point1.X + ox, symbol->Line[l].Point1.Y + oy, symbol->Line[l].Point2.X + ox, symbol->Line[l].Point2.Y + oy, symbol->Line[l].Thickness, symbol->Line[l].Thickness, NoFlags ()); if (maxx < symbol->Line[l].Point1.X) maxx = symbol->Line[l].Point1.X; if (maxx < symbol->Line[l].Point2.X) maxx = symbol->Line[l].Point2.X; } w = maxx + symbol->Delta + ox; CreateDrawnLineOnLayer (lwidth, w, miny + oy, w, maxy + oy, 100, 100, NoFlags ()); } for (l = 0; l < 16; l++) { int x = (l + 1) * CELL_SIZE; CreateDrawnLineOnLayer (lgrid, x, 0, x, PCB->MaxHeight, 100, 100, NoFlags ()); } for (l = 0; l <= MAX_FONTPOSITION / 16 + 1; l++) { int y = (l + 1) * CELL_SIZE; CreateDrawnLineOnLayer (lgrid, 0, y, PCB->MaxWidth, y, 100, 100, NoFlags ()); } return 0; }
static float drc_lines (PointTypePtr end, bool way) { float f, s, f2, s2, len, best; LocationType dx, dy, temp, last, length; LocationType temp2, last2, length2; LineType line1, line2; Cardinal group, comp; struct drc_info info; bool two_lines, x_is_long, blocker; PointType ans; f = 1.0; s = 0.5; last = -1; line1.Flags = line2.Flags = NoFlags (); line1.Thickness = Settings.LineThickness + 2 * (PCB->Bloat + 1); line2.Thickness = line1.Thickness; line1.Clearance = line2.Clearance = 0; line1.Point1.X = Crosshair.AttachedLine.Point1.X; line1.Point1.Y = Crosshair.AttachedLine.Point1.Y; dy = end->Y - line1.Point1.Y; dx = end->X - line1.Point1.X; if (abs (dx) > abs (dy)) { x_is_long = true; length = abs (dx); } else { x_is_long = false; length = abs (dy); } group = GetGroupOfLayer (INDEXOFCURRENT); comp = max_group + 10; /* this out-of-range group might save a call */ if (GetLayerGroupNumberByNumber (solder_silk_layer) == group) info.solder = true; else { info.solder = false; comp = GetLayerGroupNumberByNumber (component_silk_layer); } temp = length; /* assume the worst */ best = 0.0; ans.X = line1.Point1.X; ans.Y = line1.Point1.Y; while (length != last) { last = length; if (x_is_long) { dx = SGN (dx) * length; dy = end->Y - line1.Point1.Y; length2 = abs (dy); } else { dy = SGN (dy) * length; dx = end->X - line1.Point1.X; length2 = abs (dx); } temp2 = length2; f2 = 1.0; s2 = 0.5; last2 = -1; blocker = true; while (length2 != last2) { if (x_is_long) dy = SGN (dy) * length2; else dx = SGN (dx) * length2; two_lines = true; if (abs (dx) > abs (dy) && x_is_long) { line1.Point2.X = line1.Point1.X + (way ? SGN (dx) * abs (dy) : dx - SGN (dx) * abs (dy)); line1.Point2.Y = line1.Point1.Y + (way ? dy : 0); } else if (abs (dy) >= abs (dx) && !x_is_long) { line1.Point2.X = line1.Point1.X + (way ? dx : 0); line1.Point2.Y = line1.Point1.Y + (way ? SGN (dy) * abs (dx) : dy - SGN (dy) * abs (dx)); } else if (x_is_long) { /* we've changed which axis is long, so only do one line */ line1.Point2.X = line1.Point1.X + dx; line1.Point2.Y = line1.Point1.Y + (way ? SGN (dy) * abs (dx) : 0); two_lines = false; } else { /* we've changed which axis is long, so only do one line */ line1.Point2.Y = line1.Point1.Y + dy; line1.Point2.X = line1.Point1.X + (way ? SGN (dx) * abs (dy) : 0); two_lines = false; } line2.Point1.X = line1.Point2.X; line2.Point1.Y = line1.Point2.Y; if (!two_lines) { line2.Point2.Y = line1.Point2.Y; line2.Point2.X = line1.Point2.X; } else { line2.Point2.X = line1.Point1.X + dx; line2.Point2.Y = line1.Point1.Y + dy; } SetLineBoundingBox (&line1); SetLineBoundingBox (&line2); last2 = length2; if (setjmp (info.env) == 0) { info.line = &line1; r_search (PCB->Data->via_tree, &line1.BoundingBox, NULL, drcVia_callback, &info); r_search (PCB->Data->pin_tree, &line1.BoundingBox, NULL, drcVia_callback, &info); if (info.solder || comp == group) r_search (PCB->Data->pad_tree, &line1.BoundingBox, NULL, drcPad_callback, &info); if (two_lines) { info.line = &line2; r_search (PCB->Data->via_tree, &line2.BoundingBox, NULL, drcVia_callback, &info); r_search (PCB->Data->pin_tree, &line2.BoundingBox, NULL, drcVia_callback, &info); if (info.solder || comp == group) r_search (PCB->Data->pad_tree, &line2.BoundingBox, NULL, drcPad_callback, &info); } GROUP_LOOP (PCB->Data, group); { info.line = &line1; r_search (layer->line_tree, &line1.BoundingBox, NULL, drcLine_callback, &info); r_search (layer->arc_tree, &line1.BoundingBox, NULL, drcArc_callback, &info); if (two_lines) { info.line = &line2; r_search (layer->line_tree, &line2.BoundingBox, NULL, drcLine_callback, &info); r_search (layer->arc_tree, &line2.BoundingBox, NULL, drcArc_callback, &info); } } END_LOOP; /* no intersector! */ blocker = false; f2 += s2; len = (line2.Point2.X - line1.Point1.X); len *= len; len += (float) (line2.Point2.Y - line1.Point1.Y) * (line2.Point2.Y - line1.Point1.Y); if (len > best) { best = len; ans.X = line2.Point2.X; ans.Y = line2.Point2.Y; } #if 0 if (f2 > 1.0) f2 = 0.5; #endif } else { /* bumped into something, back off */ f2 -= s2; } s2 *= 0.5; length2 = MIN (f2 * temp2, temp2); } if (!blocker && ((x_is_long && line2.Point2.X - line1.Point1.X == dx) || (!x_is_long && line2.Point2.Y - line1.Point1.Y == dy))) f += s; else f -= s; s *= 0.5; length = MIN (f * temp, temp); } end->X = ans.X; end->Y = ans.Y; return best; }
/* --------------------------------------------------------------------------- * draws additional stuff that follows the crosshair */ void DrawAttached (void) { switch (Settings.Mode) { case VIA_MODE: { /* Make a dummy via structure to draw from */ PinType via; via.X = Crosshair.X; via.Y = Crosshair.Y; via.Thickness = Settings.ViaThickness; via.Clearance = 2 * Settings.Keepaway; via.DrillingHole = Settings.ViaDrillingHole; via.Mask = 0; via.Flags = NoFlags (); gui->thindraw_pcb_pv (Crosshair.GC, Crosshair.GC, &via, true, false); if (TEST_FLAG (SHOWDRCFLAG, PCB)) { /* XXX: Naughty cheat - use the mask to draw DRC clearance! */ via.Mask = Settings.ViaThickness + PCB->Bloat * 2; gui->set_color (Crosshair.GC, Settings.CrossColor); gui->thindraw_pcb_pv (Crosshair.GC, Crosshair.GC, &via, false, true); gui->set_color (Crosshair.GC, Settings.CrosshairColor); } break; } /* the attached line is used by both LINEMODE, POLYGON_MODE and POLYGONHOLE_MODE*/ case POLYGON_MODE: case POLYGONHOLE_MODE: /* draw only if starting point is set */ if (Crosshair.AttachedLine.State != STATE_FIRST) gui->draw_line (Crosshair.GC, Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y); /* draw attached polygon only if in POLYGON_MODE or POLYGONHOLE_MODE */ if (Crosshair.AttachedPolygon.PointN > 1) { XORPolygon (&Crosshair.AttachedPolygon, 0, 0); } break; case ARC_MODE: if (Crosshair.AttachedBox.State != STATE_FIRST) { XORDrawAttachedArc (Settings.LineThickness); if (TEST_FLAG (SHOWDRCFLAG, PCB)) { gui->set_color (Crosshair.GC, Settings.CrossColor); XORDrawAttachedArc (Settings.LineThickness + 2 * (PCB->Bloat + 1)); gui->set_color (Crosshair.GC, Settings.CrosshairColor); } } break; case LINE_MODE: /* draw only if starting point exists and the line has length */ if (Crosshair.AttachedLine.State != STATE_FIRST && Crosshair.AttachedLine.draw) { XORDrawAttachedLine (Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y, PCB->RatDraw ? 10 : Settings.LineThickness); /* draw two lines ? */ if (PCB->Clipping) XORDrawAttachedLine (Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y, Crosshair.X, Crosshair.Y, PCB->RatDraw ? 10 : Settings.LineThickness); if (TEST_FLAG (SHOWDRCFLAG, PCB)) { gui->set_color (Crosshair.GC, Settings.CrossColor); XORDrawAttachedLine (Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y, PCB->RatDraw ? 10 : Settings.LineThickness + 2 * (PCB->Bloat + 1)); if (PCB->Clipping) XORDrawAttachedLine (Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y, Crosshair.X, Crosshair.Y, PCB->RatDraw ? 10 : Settings. LineThickness + 2 * (PCB->Bloat + 1)); gui->set_color (Crosshair.GC, Settings.CrosshairColor); } } break; case PASTEBUFFER_MODE: XORDrawBuffer (PASTEBUFFER); break; case COPY_MODE: case MOVE_MODE: XORDrawMoveOrCopyObject (); break; case INSERTPOINT_MODE: XORDrawInsertPointObject (); break; } /* an attached box does not depend on a special mode */ if (Crosshair.AttachedBox.State == STATE_SECOND || Crosshair.AttachedBox.State == STATE_THIRD) { Coord x1, y1, x2, y2; x1 = Crosshair.AttachedBox.Point1.X; y1 = Crosshair.AttachedBox.Point1.Y; x2 = Crosshair.AttachedBox.Point2.X; y2 = Crosshair.AttachedBox.Point2.Y; gui->draw_rect (Crosshair.GC, x1, y1, x2, y2); } }
/*--------------------------------------------------------------------------- * * break buffer element into pieces */ bool SmashBufferElement (BufferType *Buffer) { ElementType *element; Cardinal group; LayerType *clayer, *slayer; if (Buffer->Data->ElementN != 1) { Message (_("Error! Buffer doesn't contain a single element\n")); return (false); } /* * At this point the buffer should contain just a single element. * Now we detach the single element from the buffer and then clear the * buffer, ready to receive the smashed elements. As a result of detaching * it the single element is orphaned from the buffer and thus will not be * free()'d by FreeDataMemory (called via ClearBuffer). This leaves it * around for us to smash bits off it. It then becomes our responsibility, * however, to free the single element when we're finished with it. */ element = Buffer->Data->Element->data; Buffer->Data->Element = NULL; Buffer->Data->ElementN = 0; ClearBuffer (Buffer); ELEMENTLINE_LOOP (element); { CreateNewLineOnLayer (&Buffer->Data->SILKLAYER, line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y, line->Thickness, 0, NoFlags ()); if (line) line->Number = STRDUP (NAMEONPCB_NAME (element)); } END_LOOP; ARC_LOOP (element); { CreateNewArcOnLayer (&Buffer->Data->SILKLAYER, arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle, arc->Delta, arc->Thickness, 0, NoFlags ()); } END_LOOP; PIN_LOOP (element); { FlagType f = NoFlags (); AddFlags (f, VIAFLAG); if (TEST_FLAG (HOLEFLAG, pin)) AddFlags (f, HOLEFLAG); CreateNewVia (Buffer->Data, pin->X, pin->Y, pin->Thickness, pin->Clearance, pin->Mask, pin->DrillingHole, pin->Number, f); } END_LOOP; group = GetLayerGroupNumberByNumber (SWAP_IDENT ? solder_silk_layer : component_silk_layer); clayer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]]; group = GetLayerGroupNumberByNumber (SWAP_IDENT ? component_silk_layer : solder_silk_layer); slayer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]]; PAD_LOOP (element); { LineType *line; line = CreateNewLineOnLayer (TEST_FLAG (ONSOLDERFLAG, pad) ? slayer : clayer, pad->Point1.X, pad->Point1.Y, pad->Point2.X, pad->Point2.Y, pad->Thickness, pad->Clearance, NoFlags ()); if (line) line->Number = STRDUP (pad->Number); } END_LOOP; FreeElementMemory (element); g_slice_free (ElementType, element); return (true); }
/* ThermPoly returns a POLYAREA having all of the clearance that when * subtracted from the plane create the desired thermal fingers. * Usually this is 4 disjoint regions. * */ POLYAREA * ThermPoly (PCBTypePtr p, PinTypePtr pin, Cardinal laynum) { ArcType a; POLYAREA *pa, *arc; Cardinal style = GET_THERM (laynum, pin); if (style == 3) return NULL; /* solid connection no clearance */ pcb = p; if (TEST_FLAG (SQUAREFLAG, pin)) return square_therm (pin, style); if (TEST_FLAG (OCTAGONFLAG, pin)) return oct_therm (pin, style); /* must be circular */ switch (style) { case 1: case 2: { POLYAREA *m; Coord t = (pin->Thickness + pin->Clearance) / 2; Coord w = 0.5 * pcb->ThermScale * pin->Clearance; pa = CirclePoly (pin->X, pin->Y, t); arc = CirclePoly (pin->X, pin->Y, pin->Thickness / 2); /* create a thin ring */ poly_Boolean_free (pa, arc, &m, PBO_SUB); /* fix me needs error checking */ if (style == 2) { /* t is the theoretically required length, but we use twice that * to avoid descritisation errors in our circle approximation. */ pa = RectPoly (pin->X - t * 2, pin->X + t * 2, pin->Y - w, pin->Y + w); poly_Boolean_free (m, pa, &arc, PBO_SUB); pa = RectPoly (pin->X - w, pin->X + w, pin->Y - t * 2, pin->Y + t * 2); } else { /* t is the theoretically required length, but we use twice that * to avoid descritisation errors in our circle approximation. */ pa = diag_line (pin->X, pin->Y, t * 2, w, true); poly_Boolean_free (m, pa, &arc, PBO_SUB); pa = diag_line (pin->X, pin->Y, t * 2, w, false); } poly_Boolean_free (arc, pa, &m, PBO_SUB); return m; } default: a.X = pin->X; a.Y = pin->Y; a.Height = a.Width = pin->Thickness / 2 + pin->Clearance / 4; a.Thickness = 1; a.Clearance = pin->Clearance / 2; a.Flags = NoFlags (); a.Delta = 90 - (a.Clearance * (1. + 2. * pcb->ThermScale) * 180) / (M_PI * a.Width); a.StartAngle = 90 - a.Delta / 2 + (style == 4 ? 0 : 45); pa = ArcPoly (&a, a.Clearance); if (!pa) return NULL; a.StartAngle += 90; arc = ArcPoly (&a, a.Clearance); if (!arc) return NULL; pa->f = arc; arc->b = pa; a.StartAngle += 90; arc = ArcPoly (&a, a.Clearance); if (!arc) return NULL; pa->f->f = arc; arc->b = pa->f; a.StartAngle += 90; arc = ArcPoly (&a, a.Clearance); if (!arc) return NULL; pa->b = arc; pa->f->f->f = arc; arc->b = pa->f->f; arc->f = pa; pa->b = arc; return pa; } }
static POLYAREA * square_therm (PinTypePtr pin, Cardinal style) { POLYAREA *p, *p2; PLINE *c; Vector v; Coord d, in, out; switch (style) { case 1: d = pcb->ThermScale * pin->Clearance * M_SQRT1_2; out = (pin->Thickness + pin->Clearance) / 2; in = pin->Thickness / 2; /* top (actually bottom since +y is down) */ v[0] = pin->X - in + d; v[1] = pin->Y + in; if ((c = poly_NewContour (v)) == NULL) return NULL; v[0] = pin->X + in - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X + out - d; v[1] = pin->Y + out; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X - out + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); p = ContourToPoly (c); /* right */ v[0] = pin->X + in; v[1] = pin->Y + in - d; if ((c = poly_NewContour (v)) == NULL) return NULL; v[1] = pin->Y - in + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X + out; v[1] = pin->Y - out + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[1] = pin->Y + out - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); p2 = ContourToPoly (c); p->f = p2; p2->b = p; /* left */ v[0] = pin->X - in; v[1] = pin->Y - in + d; if ((c = poly_NewContour (v)) == NULL) return NULL; v[1] = pin->Y + in - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X - out; v[1] = pin->Y + out - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[1] = pin->Y - out + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); p2 = ContourToPoly (c); p->f->f = p2; p2->b = p->f; /* bottom (actually top since +y is down) */ v[0] = pin->X + in - d; v[1] = pin->Y - in; if ((c = poly_NewContour (v)) == NULL) return NULL; v[0] = pin->X - in + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X - out + d; v[1] = pin->Y - out; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X + out - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); p2 = ContourToPoly (c); p->f->f->f = p2; p2->f = p; p2->b = p->f->f; p->b = p2; return p; case 4: { LineType l; l.Flags = NoFlags (); d = pin->Thickness / 2 - pcb->ThermScale * pin->Clearance; out = pin->Thickness / 2 + pin->Clearance / 4; in = pin->Clearance / 2; /* top */ l.Point1.X = pin->X - d; l.Point2.Y = l.Point1.Y = pin->Y + out; l.Point2.X = pin->X + d; p = LinePoly (&l, in); /* right */ l.Point1.X = l.Point2.X = pin->X + out; l.Point1.Y = pin->Y - d; l.Point2.Y = pin->Y + d; p2 = LinePoly (&l, in); p->f = p2; p2->b = p; /* bottom */ l.Point1.X = pin->X - d; l.Point2.Y = l.Point1.Y = pin->Y - out; l.Point2.X = pin->X + d; p2 = LinePoly (&l, in); p->f->f = p2; p2->b = p->f; /* left */ l.Point1.X = l.Point2.X = pin->X - out; l.Point1.Y = pin->Y - d; l.Point2.Y = pin->Y + d; p2 = LinePoly (&l, in); p->f->f->f = p2; p2->b = p->f->f; p->b = p2; p2->f = p; return p; } default: /* style 2 and 5 */ d = 0.5 * pcb->ThermScale * pin->Clearance; if (style == 5) d += d; out = (pin->Thickness + pin->Clearance) / 2; in = pin->Thickness / 2; /* topright */ v[0] = pin->X + in; v[1] = pin->Y + in; if ((c = poly_NewContour (v)) == NULL) return NULL; v[1] = pin->Y + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 2) { v[0] = pin->X + out; poly_InclVertex (c->head.prev, poly_CreateNode (v)); } else frac_circle (c, v[0] + pin->Clearance / 4, v[1], v, 2); v[1] = pin->Y + in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); /* pivot 1/4 circle to next point */ frac_circle (c, pin->X + in, pin->Y + in, v, 4); v[0] = pin->X + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 2) { poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[1] = pin->Y + in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); } else frac_circle (c, v[0], v[1] - pin->Clearance / 4, v, 2); p = ContourToPoly (c); /* bottom right */ v[0] = pin->X + in; v[1] = pin->Y - d; if ((c = poly_NewContour (v)) == NULL) return NULL; v[1] = pin->Y - in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 2) { v[1] = pin->Y - out; poly_InclVertex (c->head.prev, poly_CreateNode (v)); } else frac_circle (c, v[0], v[1] - pin->Clearance / 4, v, 2); v[0] = pin->X + in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); /* pivot 1/4 circle to next point */ frac_circle (c, pin->X + in, pin->Y - in, v, 4); v[1] = pin->Y - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 5) frac_circle (c, v[0] - pin->Clearance / 4, v[1], v, 2); p2 = ContourToPoly (c); p->f = p2; p2->b = p; /* bottom left */ v[0] = pin->X - d; v[1] = pin->Y - in; if ((c = poly_NewContour (v)) == NULL) return NULL; v[0] = pin->X - in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[1] = pin->Y - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 2) { v[0] = pin->X - out; poly_InclVertex (c->head.prev, poly_CreateNode (v)); } else frac_circle (c, v[0] - pin->Clearance / 4, v[1], v, 2); v[1] = pin->Y - in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); /* pivot 1/4 circle to next point */ frac_circle (c, pin->X - in, pin->Y - in, v, 4); v[0] = pin->X - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 5) frac_circle (c, v[0], v[1] + pin->Clearance / 4, v, 2); p2 = ContourToPoly (c); p->f->f = p2; p2->b = p->f; /* top left */ v[0] = pin->X - d; v[1] = pin->Y + out; if ((c = poly_NewContour (v)) == NULL) return NULL; v[0] = pin->X - in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); /* pivot 1/4 circle to next point (x-out, y+in) */ frac_circle (c, pin->X - in, pin->Y + in, v, 4); v[1] = pin->Y + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 2) { v[0] = pin->X - in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); } else frac_circle (c, v[0] + pin->Clearance / 4, v[1], v, 2); v[1] = pin->Y + in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 5) frac_circle (c, v[0], v[1] + pin->Clearance / 4, v, 2); p2 = ContourToPoly (c); p->f->f->f = p2; p2->f = p; p2->b = p->f->f; p->b = p2; return p; } }
static int FontEdit (int argc, char **argv, Coord Ux, Coord Uy) { FontType *font; SymbolType *symbol; LayerType *lfont, *lorig, *lwidth, *lgrid; int s, l; if (hid_actionl ("New", "Font", 0)) { return 1; } Settings.grid_unit = get_unit_struct("mil"); Settings.Bloat = PCB->Bloat = 1; Settings.Shrink = PCB->Shrink = 1; Settings.minWid = PCB->minWid = 1; Settings.minSlk = PCB->minSlk = 1; MoveLayerToGroup (max_copper_layer + TOP_SILK_LAYER, 0); MoveLayerToGroup (max_copper_layer + BOTTOM_SILK_LAYER, 1); while (PCB->Data->LayerN > 4) { MoveLayer (4, -1); } for (l = 0; l < 4; l++) { MoveLayerToGroup (l, l); } PCB->MaxWidth = CELL_SIZE * 18; PCB->MaxHeight = CELL_SIZE * ((MAX_FONTPOSITION + 15) / 16 + 2); PCB->Grid = MIL_TO_COORD (5); PCB->Data->Layer[0].Name = strdup ("Font"); PCB->Data->Layer[1].Name = strdup ("OrigFont"); PCB->Data->Layer[2].Name = strdup ("Width"); PCB->Data->Layer[3].Name = strdup ("Grid"); hid_action ("PCBChanged"); hid_action ("LayersChanged"); lfont = PCB->Data->Layer + 0; lorig = PCB->Data->Layer + 1; lwidth = PCB->Data->Layer + 2; lgrid = PCB->Data->Layer + 3; font = &PCB->Font; for (s = 0; s <= MAX_FONTPOSITION; s++) { Coord ox = (s % 16 + 1) * CELL_SIZE; Coord oy = (s / 16 + 1) * CELL_SIZE; Coord w, miny, maxy, maxx = 0; symbol = &font->Symbol[s]; miny = MIL_TO_COORD (5); maxy = font->MaxHeight; for (l = 0; l < symbol->LineN; l++) { CreateDrawnLineOnLayer (lfont, symbol->Line[l].Point1.X + ox, symbol->Line[l].Point1.Y + oy, symbol->Line[l].Point2.X + ox, symbol->Line[l].Point2.Y + oy, symbol->Line[l].Thickness, symbol->Line[l].Thickness, NoFlags ()); CreateDrawnLineOnLayer (lorig, symbol->Line[l].Point1.X + ox, symbol->Line[l].Point1.Y + oy, symbol->Line[l].Point2.X + ox, symbol->Line[l].Point2.Y + oy, symbol->Line[l].Thickness, symbol->Line[l].Thickness, NoFlags ()); if (maxx < symbol->Line[l].Point1.X) { maxx = symbol->Line[l].Point1.X; } if (maxx < symbol->Line[l].Point2.X) { maxx = symbol->Line[l].Point2.X; } } w = maxx + symbol->Delta + ox; CreateDrawnLineOnLayer (lwidth, w, miny + oy, w, maxy + oy, MIL_TO_COORD (1), MIL_TO_COORD (1), NoFlags ()); } for (l = 0; l < 16; l++) { int x = (l + 1) * CELL_SIZE; CreateDrawnLineOnLayer (lgrid, x, 0, x, PCB->MaxHeight, MIL_TO_COORD (1), MIL_TO_COORD (1), NoFlags ()); } for (l = 0; l <= MAX_FONTPOSITION / 16 + 1; l++) { int y = (l + 1) * CELL_SIZE; CreateDrawnLineOnLayer (lgrid, 0, y, PCB->MaxWidth, y, MIL_TO_COORD (1), MIL_TO_COORD (1), NoFlags ()); } return 0; }
/*--------------------------------------------------------------------------- * * convert buffer contents into an element */ bool ConvertBufferToElement (BufferType *Buffer) { ElementType *Element; Cardinal group; Cardinal pin_n = 1; bool hasParts = false, crooked = false; int onsolder; bool warned = false; if (Buffer->Data->pcb == 0) Buffer->Data->pcb = PCB; Element = CreateNewElement (PCB->Data, &PCB->Font, NoFlags (), NULL, NULL, NULL, PASTEBUFFER->X, PASTEBUFFER->Y, 0, 100, MakeFlags (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG), false); if (!Element) return (false); VIA_LOOP (Buffer->Data); { char num[8]; if (via->Mask < via->Thickness) via->Mask = via->Thickness + 2 * MASKFRAME; if (via->Name) CreateNewPin (Element, via->X, via->Y, via->Thickness, via->Clearance, via->Mask, via->DrillingHole, NULL, via->Name, MaskFlags (via->Flags, VIAFLAG | NOCOPY_FLAGS | SELECTEDFLAG | WARNFLAG)); else { sprintf (num, "%d", pin_n++); CreateNewPin (Element, via->X, via->Y, via->Thickness, via->Clearance, via->Mask, via->DrillingHole, NULL, num, MaskFlags (via->Flags, VIAFLAG | NOCOPY_FLAGS | SELECTEDFLAG | WARNFLAG)); } hasParts = true; } END_LOOP; for (onsolder = 0; onsolder < 2; onsolder ++) { int silk_layer; int onsolderflag; if ((!onsolder) == (!SWAP_IDENT)) { silk_layer = component_silk_layer; onsolderflag = NOFLAG; } else { silk_layer = solder_silk_layer; onsolderflag = ONSOLDERFLAG; } #define MAYBE_WARN() \ if (onsolder && !hasParts && !warned) \ { \ warned = true; \ Message \ (_("Warning: All of the pads are on the opposite\n" \ "side from the component - that's probably not what\n" \ "you wanted\n")); \ } \ /* get the component-side SM pads */ group = GetLayerGroupNumberByNumber (silk_layer); GROUP_LOOP (Buffer->Data, group); { char num[8]; LINE_LOOP (layer); { sprintf (num, "%d", pin_n++); CreateNewPad (Element, line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y, line->Thickness, line->Clearance, line->Thickness + line->Clearance, NULL, line->Number ? line->Number : num, MakeFlags (onsolderflag)); MAYBE_WARN(); hasParts = true; } END_LOOP; POLYGON_LOOP (layer); { Coord x1, y1, x2, y2, w, h, t; if (! polygon_is_rectangle (polygon)) { crooked = true; continue; } w = polygon->Points[2].X - polygon->Points[0].X; h = polygon->Points[1].Y - polygon->Points[0].Y; t = (w < h) ? w : h; x1 = polygon->Points[0].X + t/2; y1 = polygon->Points[0].Y + t/2; x2 = x1 + (w-t); y2 = y1 + (h-t); sprintf (num, "%d", pin_n++); CreateNewPad (Element, x1, y1, x2, y2, t, 2 * Settings.Keepaway, t + Settings.Keepaway, NULL, num, MakeFlags (SQUAREFLAG | onsolderflag)); MAYBE_WARN(); hasParts = true; } END_LOOP; } END_LOOP; } /* now add the silkscreen. NOTE: elements must have pads or pins too */ LINE_LOOP (&Buffer->Data->SILKLAYER); { if (line->Number && !NAMEONPCB_NAME (Element)) NAMEONPCB_NAME (Element) = strdup (line->Number); CreateNewLineInElement (Element, line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y, line->Thickness); hasParts = true; } END_LOOP; ARC_LOOP (&Buffer->Data->SILKLAYER); { CreateNewArcInElement (Element, arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle, arc->Delta, arc->Thickness); hasParts = true; } END_LOOP; if (!hasParts) { DestroyObject (PCB->Data, ELEMENT_TYPE, Element, Element, Element); Message (_("There was nothing to convert!\n" "Elements must have some silk, pads or pins.\n")); return (false); } if (crooked) Message (_("There were polygons that can't be made into pins!\n" "So they were not included in the element\n")); Element->MarkX = Buffer->X; Element->MarkY = Buffer->Y; if (SWAP_IDENT) SET_FLAG (ONSOLDERFLAG, Element); SetElementBoundingBox (PCB->Data, Element, &PCB->Font); ClearBuffer (Buffer); MoveObjectToBuffer (Buffer->Data, PCB->Data, ELEMENT_TYPE, Element, Element, Element); SetBufferBoundingBox (Buffer); return (true); }
/*! * \brief This function is moved from the original netlist.c as * part of the gui code separation for the Gtk port. */ RatType * AddNet (void) { static int ratDrawn = 0; char name1[256], *name2; Cardinal group1, group2; char ratname[20]; int found; void *ptr1, *ptr2, *ptr3; LibraryMenuType *menu; LibraryEntryType *entry; if (Crosshair.AttachedLine.Point1.X == Crosshair.AttachedLine.Point2.X && Crosshair.AttachedLine.Point1.Y == Crosshair.AttachedLine.Point2.Y) return (NULL); found = SearchObjectByLocation (PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3, Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, 5); if (found == NO_TYPE) { Message (_("No pad/pin under rat line\n")); return (NULL); } if (NAMEONPCB_NAME ((ElementType *) ptr1) == NULL || *NAMEONPCB_NAME ((ElementType *) ptr1) == 0) { Message (_("You must name the starting element first\n")); return (NULL); } /* will work for pins to since the FLAG is common */ group1 = GetLayerGroupNumberBySide ( TEST_FLAG (ONSOLDERFLAG, (PadType *) ptr2) ? BOTTOM_SIDE : TOP_SIDE); strcpy (name1, ConnectionName (found, ptr1, ptr2)); found = SearchObjectByLocation (PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3, Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y, 5); if (found == NO_TYPE) { Message (_("No pad/pin under rat line\n")); return (NULL); } if (NAMEONPCB_NAME ((ElementType *) ptr1) == NULL || *NAMEONPCB_NAME ((ElementType *) ptr1) == 0) { Message (_("You must name the ending element first\n")); return (NULL); } group2 = GetLayerGroupNumberBySide ( TEST_FLAG (ONSOLDERFLAG, (PadType *) ptr2) ? BOTTOM_SIDE : TOP_SIDE); name2 = ConnectionName (found, ptr1, ptr2); menu = netnode_to_netname (name1); if (menu) { if (netnode_to_netname (name2)) { Message (_ ("Both connections already in netlist - cannot merge nets\n")); return (NULL); } entry = GetLibraryEntryMemory (menu); entry->ListEntry = strdup (name2); netnode_to_netname (name2); goto ratIt; } /* ok, the first name did not belong to a net */ menu = netnode_to_netname (name2); if (menu) { entry = GetLibraryEntryMemory (menu); entry->ListEntry = strdup (name1); netnode_to_netname (name1); goto ratIt; } /* * neither belong to a net, so create a new one. * * before creating a new rats here, we need to search * for a unique name. */ sprintf (ratname, " ratDrawn%i", ++ratDrawn); while (rat_used (ratname)) { sprintf (ratname, " ratDrawn%i", ++ratDrawn); } menu = GetLibraryMenuMemory (&PCB->NetlistLib); menu->Name = strdup (ratname); entry = GetLibraryEntryMemory (menu); entry->ListEntry = strdup (name1); entry = GetLibraryEntryMemory (menu); entry->ListEntry = strdup (name2); menu->flag = 1; ratIt: NetlistChanged (0); return (CreateNewRat (PCB->Data, Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y, group1, group2, Settings.RatThickness, NoFlags ())); }
/*! * \brief Draw a rat net (tree) having the shortest lines. * * This also frees the subnet memory as they are consumed. * * \note The \c Netl we are passed is NOT the main netlist - it's the * connectivity for ONE net. * It represents the CURRENT connectivity state for the net, with each * Netl->Net[N] representing one copper-connected subset of the net. * * Everything inside the NetList Netl should be connected together. * * Each Net in \c Netl is a group of Connections which are already * connected together somehow, either by real wires or by rats we've * already drawn. * * Each Connection is a vertex within that blob of connected items. * * This loop finds the closest vertex pairs between each blob and draws * rats that merge the blobs until there's just one big blob. * * Just to clarify, with some examples: * * Each \c Netl is one full net from a netlist, like from gnetlist. * * Each Netl->Net[N] is a subset of that net that's already * physically connected on the pcb. * * So a new design with no traces yet, would have a huge list of Net[N], * each with one pin in it. * * A fully routed design would have one Net[N] with all the pins * (for that net) in it. */ static bool DrawShortestRats (NetListType *Netl, void (*funcp) (register ConnectionType *, register ConnectionType *, register RouteStyleType *)) { RatType *line; register float distance, temp; register ConnectionType *conn1, *conn2, *firstpoint, *secondpoint; PolygonType *polygon; bool changed = false; bool havepoints; Cardinal n, m, j; NetType *next, *subnet, *theSubnet = NULL; /* This is just a sanity check, to make sure we're passed * *something*. */ if (!Netl || Netl->NetN < 1) return false; /* * We keep doing this do/while loop until everything's connected. * I.e. once per rat we add. */ distance = 0.0; havepoints = true; /* so we run the loop at least once */ while (Netl->NetN > 1 && havepoints) { /* This is the top of the "find one rat" logic. */ havepoints = false; firstpoint = secondpoint = NULL; /* Test Net[0] vs Net[N] for N=1..max. Find the shortest distance between any two points in different blobs. */ subnet = &Netl->Net[0]; for (j = 1; j < Netl->NetN; j++) { /* * Scan between Net[0] blob (subnet) and Net[N] blob (next). * Note the shortest distance we find. */ next = &Netl->Net[j]; for (n = subnet->ConnectionN - 1; n != -1; n--) { conn1 = &subnet->Connection[n]; for (m = next->ConnectionN - 1; m != -1; m--) { conn2 = &next->Connection[m]; /* * At this point, conn1 and conn2 are two pins in * different blobs of the same net. See how far * apart they are, and if they're "closer" than what * we already have. */ /* * Prefer to connect Connections over polygons to the * polygons (ie assume the user wants a via to a plane, * not a daisy chain). Further prefer to pick an existing * via in the Net to make that connection. */ if (conn1->type == POLYGON_TYPE && (polygon = (PolygonType *)conn1->ptr2) && !(distance == 0 && firstpoint && firstpoint->type == VIA_TYPE) && IsPointInPolygonIgnoreHoles (conn2->X, conn2->Y, polygon)) { distance = 0; firstpoint = conn2; secondpoint = conn1; theSubnet = next; havepoints = true; } else if (conn2->type == POLYGON_TYPE && (polygon = (PolygonType *)conn2->ptr2) && !(distance == 0 && firstpoint && firstpoint->type == VIA_TYPE) && IsPointInPolygonIgnoreHoles (conn1->X, conn1->Y, polygon)) { distance = 0; firstpoint = conn1; secondpoint = conn2; theSubnet = next; havepoints = true; } else if ((temp = SQUARE (conn1->X - conn2->X) + SQUARE (conn1->Y - conn2->Y)) < distance || !firstpoint) { distance = temp; firstpoint = conn1; secondpoint = conn2; theSubnet = next; havepoints = true; } } } } /* * If HAVEPOINTS is true, we've found a pair of points in two * separate blobs of the net, and need to connect them together. */ if (havepoints) { if (funcp) { (*funcp) (firstpoint, secondpoint, subnet->Style); } else { /* found the shortest distance subnet, draw the rat */ if ((line = CreateNewRat (PCB->Data, firstpoint->X, firstpoint->Y, secondpoint->X, secondpoint->Y, firstpoint->group, secondpoint->group, Settings.RatThickness, NoFlags ())) != NULL) { if (distance == 0) SET_FLAG (VIAFLAG, line); AddObjectToCreateUndoList (RATLINE_TYPE, line, line, line); DrawRat (line); changed = true; } } /* copy theSubnet into the current subnet */ TransferNet (Netl, theSubnet, subnet); } } /* presently nothing to do with the new subnet */ /* so we throw it away and free the space */ FreeNetMemory (&Netl->Net[--(Netl->NetN)]); /* Sadly adding a rat line messes up the sorted arrays in connection finder */ /* hace: perhaps not necessarily now that they aren't stored in normal layers */ if (changed) { FreeConnectionLookupMemory (); InitConnectionLookup (); } return (changed); }