/* create an "empty space" representation */ mtspace_t * mtspace_create (void) { mtspace_t *mtspace; /* create mtspace data structure */ mtspace = (mtspace_t *)malloc (sizeof (*mtspace)); mtspace->ftree = r_create_tree (NULL, 0, 0); mtspace->etree = r_create_tree (NULL, 0, 0); mtspace->otree = r_create_tree (NULL, 0, 0); /* done! */ return mtspace; }
/* --------------------------------------------------------------------------- * 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++); }
LineTypePtr CreateNewLineOnLayer (LayerTypePtr Layer, LocationType X1, LocationType Y1, LocationType X2, LocationType Y2, BDimension Thickness, BDimension Clearance, FlagType Flags) { LineTypePtr Line; Line = GetLineMemory (Layer); if (!Line) return (Line); Line->ID = ID++; Line->Flags = Flags; CLEAR_FLAG (RATFLAG, Line); Line->Thickness = Thickness; Line->Clearance = Clearance; Line->Point1.X = X1; Line->Point1.Y = Y1; Line->Point1.ID = ID++; Line->Point2.X = X2; Line->Point2.Y = Y2; Line->Point2.ID = ID++; SetLineBoundingBox (Line); if (!Layer->line_tree) Layer->line_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->line_tree, (BoxTypePtr) Line, 0); return (Line); }
/* --------------------------------------------------------------------------- * creates a new rat-line */ RatTypePtr CreateNewRat (DataTypePtr Data, LocationType X1, LocationType Y1, LocationType X2, LocationType Y2, Cardinal group1, Cardinal group2, BDimension Thickness, FlagType Flags) { RatTypePtr Line = GetRatMemory (Data); if (!Line) return (Line); Line->ID = ID++; Line->Flags = Flags; SET_FLAG (RATFLAG, Line); Line->Thickness = Thickness; Line->Point1.X = X1; Line->Point1.Y = Y1; Line->Point1.ID = ID++; Line->Point2.X = X2; Line->Point2.Y = Y2; Line->Point2.ID = ID++; Line->group1 = group1; Line->group2 = group2; SetLineBoundingBox ((LineTypePtr) Line); if (!Data->rat_tree) Data->rat_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Data->rat_tree, &Line->BoundingBox, 0); return (Line); }
/* --------------------------------------------------------------------------- * get next slot for a polygon object, allocates memory if necessary */ PolygonTypePtr GetPolygonMemory (LayerTypePtr Layer) { PolygonTypePtr polygon = Layer->Polygon; /* realloc new memory if necessary and clear it */ if (Layer->PolygonN >= Layer->PolygonMax) { Layer->PolygonMax += STEP_POLYGON; if (Layer->polygon_tree) r_destroy_tree (&Layer->polygon_tree); polygon = MyRealloc (polygon, Layer->PolygonMax * sizeof (PolygonType), "GetPolygonMemory()"); Layer->Polygon = polygon; memset (polygon + Layer->PolygonN, 0, STEP_POLYGON * sizeof (PolygonType)); Layer->polygon_tree = r_create_tree (NULL, 0, 0); POLYGON_LOOP (Layer); { r_insert_entry (Layer->polygon_tree, (BoxType *) polygon, 0); } END_LOOP; } return (polygon + Layer->PolygonN++); }
/* --------------------------------------------------------------------------- * get next slot for a line, allocates memory if necessary */ LineTypePtr GetLineMemory (LayerTypePtr Layer) { LineTypePtr line = Layer->Line; /* realloc new memory if necessary and clear it */ if (Layer->LineN >= Layer->LineMax) { Layer->LineMax += STEP_LINE; /* all of the pointers move, so rebuild the whole tree */ if (Layer->line_tree) r_destroy_tree (&Layer->line_tree); line = MyRealloc (line, Layer->LineMax * sizeof (LineType), "GetLineMemory()"); Layer->Line = line; memset (line + Layer->LineN, 0, STEP_LINE * sizeof (LineType)); Layer->line_tree = r_create_tree (NULL, 0, 0); LINE_LOOP (Layer); { r_insert_entry (Layer->line_tree, (BoxTypePtr) line, 0); } END_LOOP; } return (line + Layer->LineN++); }
/* --------------------------------------------------------------------------- * get next slot for a Rat, allocates memory if necessary */ RatTypePtr GetRatMemory (DataTypePtr Data) { RatTypePtr rat = Data->Rat; /* realloc new memory if necessary and clear it */ if (Data->RatN >= Data->RatMax) { Data->RatMax += STEP_RAT; /* all of the pointers move, so rebuild the whole tree */ if (Data->rat_tree) r_destroy_tree (&Data->rat_tree); rat = MyRealloc (rat, Data->RatMax * sizeof (RatType), "GetRatMemory()"); Data->Rat = rat; memset (rat + Data->RatN, 0, STEP_RAT * sizeof (RatType)); Data->rat_tree = r_create_tree (NULL, 0, 0); RAT_LOOP (Data); { r_insert_entry (Data->rat_tree, (BoxTypePtr) line, 0); } END_LOOP; } return (rat + Data->RatN++); }
/* --------------------------------------------------------------------------- * moves a text object between layers; lowlevel routines */ static void * MoveTextToLayerLowLevel (LayerType *Source, TextType *text, LayerType *Destination) { RestoreToPolygon (PCB->Data, TEXT_TYPE, Source, text); r_delete_entry (Source->text_tree, (BoxType *)text); Source->Text = g_list_remove (Source->Text, text); Source->TextN --; Destination->Text = g_list_append (Destination->Text, text); Destination->TextN ++; if (GetLayerGroupNumberByNumber (solder_silk_layer) == GetLayerGroupNumberByPointer (Destination)) SET_FLAG (ONSOLDERFLAG, text); else CLEAR_FLAG (ONSOLDERFLAG, text); /* re-calculate the bounding box (it could be mirrored now) */ SetTextBoundingBox (&PCB->Font, text); if (!Destination->text_tree) Destination->text_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Destination->text_tree, (BoxType *)text, 0); ClearFromPolygon (PCB->Data, TEXT_TYPE, Destination, text); return text; }
LineType * CreateNewLineOnLayer (LayerType *Layer, Coord X1, Coord Y1, Coord X2, Coord Y2, Coord Thickness, Coord Clearance, FlagType Flags) { LineType *Line; Line = GetLineMemory (Layer); if (!Line) return (Line); Line->ID = ID++; Line->Flags = Flags; CLEAR_FLAG (RATFLAG, Line); Line->Thickness = Thickness; Line->Clearance = Clearance; Line->Point1.X = X1; Line->Point1.Y = Y1; Line->Point1.ID = ID++; Line->Point2.X = X2; Line->Point2.Y = Y2; Line->Point2.ID = ID++; SetLineBoundingBox (Line); if (!Layer->line_tree) Layer->line_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->line_tree, (BoxType *) Line, 0); return (Line); }
/* --------------------------------------------------------------------------- * creates a new text on a layer */ TextTypePtr CreateNewText (LayerTypePtr Layer, FontTypePtr PCBFont, LocationType X, LocationType Y, BYTE Direction, int Scale, char *TextString, FlagType Flags) { TextType *text; if (TextString == NULL) return NULL; text = GetTextMemory (Layer); if (text == NULL) return NULL; /* copy values, width and height are set by drawing routine * because at this point we don't know which symbols are available */ text->X = X; text->Y = Y; text->Direction = Direction; text->Flags = Flags; text->Scale = Scale; text->TextString = strdup (TextString); /* calculate size of the bounding box */ SetTextBoundingBox (PCBFont, text); text->ID = ID++; if (!Layer->text_tree) Layer->text_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->text_tree, (BoxTypePtr) text, 0); return (text); }
/* --------------------------------------------------------------------------- * moves an arc between layers; lowlevel routines */ static void * MoveArcToLayerLowLevel (LayerType *Source, ArcType *arc, LayerType *Destination) { r_delete_entry (Source->arc_tree, (BoxType *)arc); Source->Arc = g_list_remove (Source->Arc, arc); Source->ArcN --; Destination->Arc = g_list_append (Destination->Arc, arc); Destination->ArcN ++; if (!Destination->arc_tree) Destination->arc_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Destination->arc_tree, (BoxType *)arc, 0); return arc; }
/* --------------------------------------------------------------------------- * 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); }
/* --------------------------------------------------------------------------- * moves a line between layers; lowlevel routines */ static void * MoveLineToLayerLowLevel (LayerType *Source, LineType *line, LayerType *Destination) { r_delete_entry (Source->line_tree, (BoxType *)line); Source->Line = g_list_remove (Source->Line, line); Source->LineN --; Destination->Line = g_list_append (Destination->Line, line); Destination->LineN ++; if (!Destination->line_tree) Destination->line_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Destination->line_tree, (BoxType *)line, 0); return line; }
/* --------------------------------------------------------------------------- * moves a rat-line to paste buffer */ static void * MoveRatToBuffer (RatType *rat) { r_delete_entry (Source->rat_tree, (BoxType *)rat); Source->Rat = g_list_remove (Source->Rat, rat); Source->RatN --; Dest->Rat = g_list_append (Dest->Rat, rat); Dest->RatN ++; CLEAR_FLAG (NOCOPY_FLAGS, rat); if (!Dest->rat_tree) Dest->rat_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Dest->rat_tree, (BoxType *)rat, 0); return rat; }
/* --------------------------------------------------------------------------- * moves a polygon between layers; lowlevel routines */ static void * MovePolygonToLayerLowLevel (LayerType *Source, PolygonType *polygon, LayerType *Destination) { r_delete_entry (Source->polygon_tree, (BoxType *)polygon); Source->Polygon = g_list_remove (Source->Polygon, polygon); Source->PolygonN --; Destination->Polygon = g_list_append (Destination->Polygon, polygon); Destination->PolygonN ++; if (!Destination->polygon_tree) Destination->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Destination->polygon_tree, (BoxType *)polygon, 0); return polygon; }
/* --------------------------------------------------------------------------- * moves a via to paste buffer without allocating memory for the name */ static void * MoveViaToBuffer (PinType *via) { RestoreToPolygon (Source, VIA_TYPE, via, via); r_delete_entry (Source->via_tree, (BoxType *) via); Source->Via = g_list_remove (Source->Via, via); Source->ViaN --; Dest->Via = g_list_append (Dest->Via, via); Dest->ViaN ++; CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, via); if (!Dest->via_tree) Dest->via_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Dest->via_tree, (BoxType *)via, 0); ClearFromPolygon (Dest, VIA_TYPE, via, via); return via; }
/* --------------------------------------------------------------------------- * moves a text to buffer without allocating memory for the name */ static void * MoveTextToBuffer (LayerType *layer, TextType *text) { LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)]; r_delete_entry (layer->text_tree, (BoxType *)text); RestoreToPolygon (Source, TEXT_TYPE, layer, text); layer->Text = g_list_remove (layer->Text, text); layer->TextN --; lay->Text = g_list_append (lay->Text, text); lay->TextN ++; if (!lay->text_tree) lay->text_tree = r_create_tree (NULL, 0, 0); r_insert_entry (lay->text_tree, (BoxType *)text, 0); ClearFromPolygon (Dest, TEXT_TYPE, lay, text); return (text); }
/* --------------------------------------------------------------------------- * moves a polygon to buffer. Doesn't allocate memory for the points */ static void * MovePolygonToBuffer (LayerType *layer, PolygonType *polygon) { LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)]; r_delete_entry (layer->polygon_tree, (BoxType *)polygon); layer->Polygon = g_list_remove (layer->Polygon, polygon); layer->PolygonN --; lay->Polygon = g_list_append (lay->Polygon, polygon); lay->PolygonN ++; CLEAR_FLAG (NOCOPY_FLAGS, polygon); if (!lay->polygon_tree) lay->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (lay->polygon_tree, (BoxType *)polygon, 0); return (polygon); }
/* --------------------------------------------------------------------------- * creates a new polygon from the old formats rectangle data */ PolygonTypePtr CreateNewPolygonFromRectangle (LayerTypePtr Layer, LocationType X1, LocationType Y1, LocationType X2, LocationType Y2, FlagType Flags) { PolygonTypePtr polygon = CreateNewPolygon (Layer, Flags); if (!polygon) return (polygon); CreateNewPointInPolygon (polygon, X1, Y1); CreateNewPointInPolygon (polygon, X2, Y1); CreateNewPointInPolygon (polygon, X2, Y2); CreateNewPointInPolygon (polygon, X1, Y2); SetPolygonBoundingBox (polygon); if (!Layer->polygon_tree) Layer->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->polygon_tree, (BoxTypePtr) polygon, 0); return (polygon); }
/* --------------------------------------------------------------------------- * copies a polygon to buffer */ static void * AddPolygonToBuffer (LayerType *Layer, PolygonType *Polygon) { LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)]; PolygonType *polygon; polygon = CreateNewPolygon (layer, Polygon->Flags); CopyPolygonLowLevel (polygon, Polygon); /* Update the polygon r-tree. Unlike similarly named functions for * other objects, CreateNewPolygon does not do this as it creates a * skeleton polygon object, which won't have correct bounds. */ if (!layer->polygon_tree) layer->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0); CLEAR_FLAG (NOCOPY_FLAGS | ExtraFlag, polygon); return (polygon); }
/*! * \brief Creates a new polygon from the old formats rectangle data. */ PolygonType * CreateNewPolygonFromRectangle (LayerType *Layer, Coord X1, Coord Y1, Coord X2, Coord Y2, FlagType Flags) { PolygonType *polygon = CreateNewPolygon (Layer, Flags); if (!polygon) return (polygon); CreateNewPointInPolygon (polygon, X1, Y1); CreateNewPointInPolygon (polygon, X2, Y1); CreateNewPointInPolygon (polygon, X2, Y2); CreateNewPointInPolygon (polygon, X1, Y2); SetPolygonBoundingBox (polygon); if (!Layer->polygon_tree) Layer->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->polygon_tree, (BoxType *) polygon, 0); return (polygon); }
/* --------------------------------------------------------------------------- * moves a line to buffer */ static void * MoveLineToBuffer (LayerType *layer, LineType *line) { LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)]; RestoreToPolygon (Source, LINE_TYPE, layer, line); r_delete_entry (layer->line_tree, (BoxType *)line); layer->Line = g_list_remove (layer->Line, line); layer->LineN --; lay->Line = g_list_append (lay->Line, line); lay->LineN ++; CLEAR_FLAG (NOCOPY_FLAGS, line); if (!lay->line_tree) lay->line_tree = r_create_tree (NULL, 0, 0); r_insert_entry (lay->line_tree, (BoxType *)line, 0); ClearFromPolygon (Dest, LINE_TYPE, lay, line); return (line); }
/* --------------------------------------------------------------------------- * moves an arc to buffer */ static void * MoveArcToBuffer (LayerType *layer, ArcType *arc) { LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)]; RestoreToPolygon (Source, ARC_TYPE, layer, arc); r_delete_entry (layer->arc_tree, (BoxType *)arc); layer->Arc = g_list_remove (layer->Arc, arc); layer->ArcN --; lay->Arc = g_list_append (lay->Arc, arc); lay->ArcN ++; CLEAR_FLAG (NOCOPY_FLAGS, arc); if (!lay->arc_tree) lay->arc_tree = r_create_tree (NULL, 0, 0); r_insert_entry (lay->arc_tree, (BoxType *)arc, 0); ClearFromPolygon (Dest, ARC_TYPE, lay, arc); return (arc); }
/* --------------------------------------------------------------------------- * creates a new arc on a layer */ ArcTypePtr CreateNewArcOnLayer (LayerTypePtr Layer, LocationType X1, LocationType Y1, BDimension width, BDimension height, int sa, int dir, BDimension Thickness, BDimension Clearance, FlagType Flags) { ArcTypePtr Arc; ARC_LOOP (Layer); { if (arc->X == X1 && arc->Y == Y1 && arc->Width == width && (arc->StartAngle + 360) % 360 == (sa + 360) % 360 && arc->Delta == dir) return (NULL); /* prevent stacked arcs */ } END_LOOP; Arc = GetArcMemory (Layer); if (!Arc) return (Arc); Arc->ID = ID++; Arc->Flags = Flags; Arc->Thickness = Thickness; Arc->Clearance = Clearance; Arc->X = X1; Arc->Y = Y1; Arc->Width = width; Arc->Height = height; Arc->StartAngle = sa; Arc->Delta = dir; SetArcBoundingBox (Arc); if (!Layer->arc_tree) Layer->arc_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->arc_tree, (BoxTypePtr) Arc, 0); return (Arc); }
/*! * \brief Creates a new arc on a layer. */ ArcType * CreateNewArcOnLayer (LayerType *Layer, Coord X1, Coord Y1, Coord width, Coord height, Angle sa, Angle dir, Coord Thickness, Coord Clearance, FlagType Flags) { ArcType *Arc; ARC_LOOP (Layer); { if (arc->X == X1 && arc->Y == Y1 && arc->Width == width && NormalizeAngle (arc->StartAngle) == NormalizeAngle (sa) && arc->Delta == dir) return (NULL); /* prevent stacked arcs */ } END_LOOP; Arc = GetArcMemory (Layer); if (!Arc) return (Arc); Arc->ID = ID++; Arc->Flags = Flags; Arc->Thickness = Thickness; Arc->Clearance = Clearance; Arc->X = X1; Arc->Y = Y1; Arc->Width = width; Arc->Height = height; Arc->StartAngle = sa; Arc->Delta = dir; SetArcBoundingBox (Arc); if (!Layer->arc_tree) Layer->arc_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->arc_tree, (BoxType *) Arc, 0); return (Arc); }
/* --------------------------------------------------------------------------- * get next slot for a via, allocates memory if necessary */ PinTypePtr GetViaMemory (DataTypePtr Data) { PinTypePtr via = Data->Via; /* realloc new memory if necessary and clear it */ if (Data->ViaN >= Data->ViaMax) { Data->ViaMax += STEP_VIA; if (Data->via_tree) r_destroy_tree (&Data->via_tree); via = (PinTypePtr)realloc (via, Data->ViaMax * sizeof (PinType)); Data->Via = via; memset (via + Data->ViaN, 0, STEP_VIA * sizeof (PinType)); Data->via_tree = r_create_tree (NULL, 0, 0); VIA_LOOP (Data); { r_insert_entry (Data->via_tree, (BoxType *) via, 0); } END_LOOP; } return (via + Data->ViaN++); }
/* --------------------------------------------------------------------------- * get next slot for a text object, allocates memory if necessary */ TextTypePtr GetTextMemory (LayerTypePtr Layer) { TextTypePtr text = Layer->Text; /* realloc new memory if necessary and clear it */ if (Layer->TextN >= Layer->TextMax) { Layer->TextMax += STEP_TEXT; if (Layer->text_tree) r_destroy_tree (&Layer->text_tree); text = (TextTypePtr)realloc (text, Layer->TextMax * sizeof (TextType)); Layer->Text = text; memset (text + Layer->TextN, 0, STEP_TEXT * sizeof (TextType)); Layer->text_tree = r_create_tree (NULL, 0, 0); TEXT_LOOP (Layer); { r_insert_entry (Layer->text_tree, (BoxTypePtr) text, 0); } END_LOOP; } return (text + Layer->TextN++); }
/* --------------------------------------------------------------------------- * get next slot for an arc, allocates memory if necessary */ ArcTypePtr GetArcMemory (LayerTypePtr Layer) { ArcTypePtr arc = Layer->Arc; /* realloc new memory if necessary and clear it */ if (Layer->ArcN >= Layer->ArcMax) { Layer->ArcMax += STEP_ARC; if (Layer->arc_tree) r_destroy_tree (&Layer->arc_tree); arc = (ArcTypePtr)realloc (arc, Layer->ArcMax * sizeof (ArcType)); Layer->Arc = arc; memset (arc + Layer->ArcN, 0, STEP_ARC * sizeof (ArcType)); Layer->arc_tree = r_create_tree (NULL, 0, 0); ARC_LOOP (Layer); { r_insert_entry (Layer->arc_tree, (BoxTypePtr) arc, 0); } END_LOOP; } return (arc + Layer->ArcN++); }
/* --------------------------------------------------------------------------- * creates a new via */ PinTypePtr CreateNewVia (DataTypePtr Data, LocationType X, LocationType Y, BDimension Thickness, BDimension Clearance, BDimension Mask, BDimension DrillingHole, char *Name, FlagType Flags) { PinTypePtr Via; if (!be_lenient) { VIA_LOOP (Data); { if (SQUARE (via->X - X) + SQUARE (via->Y - Y) <= SQUARE (via->DrillingHole / 2 + DrillingHole / 2)) { Message (_("Dropping via at (%d, %d) because it's hole would overlap with the via " "at (%d, %d)\n"), X/100, Y/100, via->X/100, via->Y/100); return (NULL); /* don't allow via stacking */ } } END_LOOP; } Via = GetViaMemory (Data); if (!Via) return (Via); /* copy values */ Via->X = X; Via->Y = Y; Via->Thickness = Thickness; Via->Clearance = Clearance; Via->Mask = Mask; Via->DrillingHole = vendorDrillMap (DrillingHole); if (Via->DrillingHole != DrillingHole) { Message (_ ("Mapped via drill hole to %.2f mils from %.2f mils per vendor table\n"), 0.01 * Via->DrillingHole, 0.01 * DrillingHole); } Via->Name = STRDUP (Name); Via->Flags = Flags; CLEAR_FLAG (WARNFLAG, Via); SET_FLAG (VIAFLAG, Via); Via->ID = ID++; /* * don't complain about MIN_PINORVIACOPPER on a mounting hole (pure * hole) */ if (!TEST_FLAG (HOLEFLAG, Via) && (Via->Thickness < Via->DrillingHole + MIN_PINORVIACOPPER)) { Via->Thickness = Via->DrillingHole + MIN_PINORVIACOPPER; Message (_("Increased via thickness to %.2f mils to allow enough copper" " at (%.2f,%.2f).\n"), 0.01 * Via->Thickness, 0.01 * Via->X, 0.01 * Via->Y); } SetPinBoundingBox (Via); if (!Data->via_tree) Data->via_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Data->via_tree, (BoxTypePtr) Via, 0); return (Via); }
/* --------------------------------------------------------------------------- * 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); }