gerber.c: Use ` modifier in pcb-printf to fix internationalization bug
[geda-pcb/whiteaudio.git] / src / create.c
bloba199acc20ce1af12ed282a2056053a4f1d56ad6f
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
29 /* functions used to create vias, pins ...
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
36 #include <assert.h>
37 #include <memory.h>
38 #include <setjmp.h>
39 #include <stdlib.h>
41 #include "global.h"
43 #include "create.h"
44 #include "data.h"
45 #include "draw.h"
46 #include "error.h"
47 #include "mymem.h"
48 #include "misc.h"
49 #include "parse_l.h"
50 #include "pcb-printf.h"
51 #include "polygon.h"
52 #include "rtree.h"
53 #include "search.h"
54 #include "set.h"
55 #include "undo.h"
56 #include "vendor.h"
58 #ifdef HAVE_LIBDMALLOC
59 #include <dmalloc.h>
60 #endif
62 RCSID ("$Id$");
64 /* ---------------------------------------------------------------------------
65 * some local identifiers
67 static int ID = 1; /* current object ID; incremented after */
68 /* each creation of an object */
70 static bool be_lenient = false;
72 /* ----------------------------------------------------------------------
73 * some local prototypes
75 static void AddTextToElement (TextTypePtr, FontTypePtr,
76 Coord, Coord, unsigned, char *, int,
77 FlagType);
79 /* ---------------------------------------------------------------------------
80 * Set the lenience mode.
83 void
84 CreateBeLenient (bool v)
86 be_lenient = v;
89 /* ---------------------------------------------------------------------------
90 * creates a new paste buffer
92 DataTypePtr
93 CreateNewBuffer (void)
95 DataTypePtr data;
96 data = (DataTypePtr) calloc (1, sizeof (DataType));
97 data->pcb = (PCBTypePtr) PCB;
98 return data;
101 /* ---------------------------------------------------------------------------
102 * Perhaps PCB should internally just use the Settings colors? For now,
103 * use this to set PCB colors so the config can reassign PCB colors.
105 void
106 pcb_colors_from_settings (PCBTypePtr ptr)
108 int i;
110 /* copy default settings */
111 ptr->ConnectedColor = Settings.ConnectedColor;
112 ptr->ElementColor = Settings.ElementColor;
113 ptr->RatColor = Settings.RatColor;
114 ptr->InvisibleObjectsColor = Settings.InvisibleObjectsColor;
115 ptr->InvisibleMarkColor = Settings.InvisibleMarkColor;
116 ptr->ElementSelectedColor = Settings.ElementSelectedColor;
117 ptr->RatSelectedColor = Settings.RatSelectedColor;
118 ptr->PinColor = Settings.PinColor;
119 ptr->PinSelectedColor = Settings.PinSelectedColor;
120 ptr->PinNameColor = Settings.PinNameColor;
121 ptr->ViaColor = Settings.ViaColor;
122 ptr->ViaSelectedColor = Settings.ViaSelectedColor;
123 ptr->WarnColor = Settings.WarnColor;
124 ptr->MaskColor = Settings.MaskColor;
125 for (i = 0; i < MAX_LAYER; i++)
127 ptr->Data->Layer[i].Color = Settings.LayerColor[i];
128 ptr->Data->Layer[i].SelectedColor = Settings.LayerSelectedColor[i];
130 ptr->Data->Layer[component_silk_layer].Color =
131 Settings.ShowSolderSide ?
132 Settings.InvisibleObjectsColor : Settings.ElementColor;
133 ptr->Data->Layer[component_silk_layer].SelectedColor =
134 Settings.ElementSelectedColor;
135 ptr->Data->Layer[solder_silk_layer].Color =
136 Settings.ShowSolderSide ?
137 Settings.ElementColor : Settings.InvisibleObjectsColor;
138 ptr->Data->Layer[solder_silk_layer].SelectedColor =
139 Settings.ElementSelectedColor;
142 /* ---------------------------------------------------------------------------
143 * creates a new PCB
145 PCBTypePtr
146 CreateNewPCB (bool SetDefaultNames)
148 PCBTypePtr ptr;
149 int i;
151 /* allocate memory, switch all layers on and copy resources */
152 ptr = (PCBTypePtr)calloc (1, sizeof (PCBType));
153 ptr->Data = CreateNewBuffer ();
154 ptr->Data->pcb = (PCBTypePtr) ptr;
156 ptr->ThermStyle = 4;
157 ptr->IsleArea = 2.e8;
158 ptr->SilkActive = false;
159 ptr->RatDraw = false;
160 SET_FLAG (NAMEONPCBFLAG, ptr);
161 if (Settings.ShowNumber)
162 SET_FLAG (SHOWNUMBERFLAG, ptr);
163 if (Settings.AllDirectionLines)
164 SET_FLAG (ALLDIRECTIONFLAG, ptr);
165 ptr->Clipping = 1; /* this is the most useful starting point for now */
166 if (Settings.RubberBandMode)
167 SET_FLAG (RUBBERBANDFLAG, ptr);
168 if (Settings.SwapStartDirection)
169 SET_FLAG (SWAPSTARTDIRFLAG, ptr);
170 if (Settings.UniqueNames)
171 SET_FLAG (UNIQUENAMEFLAG, ptr);
172 if (Settings.SnapPin)
173 SET_FLAG (SNAPPINFLAG, ptr);
174 if (Settings.ClearLine)
175 SET_FLAG (CLEARNEWFLAG, ptr);
176 if (Settings.FullPoly)
177 SET_FLAG (NEWFULLPOLYFLAG, ptr);
178 if (Settings.OrthogonalMoves)
179 SET_FLAG (ORTHOMOVEFLAG, ptr);
180 if (Settings.liveRouting)
181 SET_FLAG (LIVEROUTEFLAG, ptr);
182 if (Settings.ShowDRC)
183 SET_FLAG (SHOWDRCFLAG, ptr);
184 if (Settings.AutoDRC)
185 SET_FLAG (AUTODRCFLAG, ptr);
186 ptr->Grid = Settings.Grid;
187 ptr->LayerGroups = Settings.LayerGroups;
188 STYLE_LOOP (ptr);
190 *style = Settings.RouteStyle[n];
191 style->index = n;
193 END_LOOP;
194 ptr->Zoom = Settings.Zoom;
195 ptr->MaxWidth = Settings.MaxWidth;
196 ptr->MaxHeight = Settings.MaxHeight;
197 ptr->ID = ID++;
198 ptr->ThermScale = 0.5;
200 ptr->Bloat = Settings.Bloat;
201 ptr->Shrink = Settings.Shrink;
202 ptr->minWid = Settings.minWid;
203 ptr->minSlk = Settings.minSlk;
204 ptr->minDrill = Settings.minDrill;
205 ptr->minRing = Settings.minRing;
207 for (i = 0; i < MAX_LAYER; i++)
208 ptr->Data->Layer[i].Name = strdup (Settings.DefaultLayerName[i]);
210 CreateDefaultFont (ptr);
212 return (ptr);
215 /* This post-processing step adds the top and bottom silk layers to a
216 * pre-existing PCB.
219 CreateNewPCBPost (PCBTypePtr pcb, int use_defaults)
221 /* copy default settings */
222 pcb_colors_from_settings (pcb);
224 if (use_defaults)
226 if (ParseGroupString (Settings.Groups, &pcb->LayerGroups, DEF_LAYER))
227 return 1;
229 pcb->Data->Layer[component_silk_layer].Name = strdup ("silk");
230 pcb->Data->Layer[solder_silk_layer].Name = strdup ("silk");
232 return 0;
235 /* ---------------------------------------------------------------------------
236 * creates a new via
238 PinTypePtr
239 CreateNewVia (DataTypePtr Data,
240 Coord X, Coord Y,
241 Coord Thickness, Coord Clearance, Coord Mask,
242 Coord DrillingHole, char *Name, FlagType Flags)
244 PinTypePtr Via;
246 if (!be_lenient)
248 VIA_LOOP (Data);
250 if (Distance (X, Y, via->X, via->Y) <=
251 via->DrillingHole / 2 + DrillingHole / 2)
253 Message (_("%m+Dropping via at %$mD because it's hole would overlap with the via "
254 "at %$mD\n"), Settings.grid_unit->allow, X, Y, via->X, via->Y);
255 return (NULL); /* don't allow via stacking */
258 END_LOOP;
261 Via = GetViaMemory (Data);
263 if (!Via)
264 return (Via);
265 /* copy values */
266 Via->X = X;
267 Via->Y = Y;
268 Via->Thickness = Thickness;
269 Via->Clearance = Clearance;
270 Via->Mask = Mask;
271 Via->DrillingHole = vendorDrillMap (DrillingHole);
272 if (Via->DrillingHole != DrillingHole)
274 Message (_("%m+Mapped via drill hole to %$mS from %$mS per vendor table\n"),
275 Settings.grid_unit->allow, Via->DrillingHole, DrillingHole);
278 Via->Name = STRDUP (Name);
279 Via->Flags = Flags;
280 CLEAR_FLAG (WARNFLAG, Via);
281 SET_FLAG (VIAFLAG, Via);
282 Via->ID = ID++;
285 * don't complain about MIN_PINORVIACOPPER on a mounting hole (pure
286 * hole)
288 if (!TEST_FLAG (HOLEFLAG, Via) &&
289 (Via->Thickness < Via->DrillingHole + MIN_PINORVIACOPPER))
291 Via->Thickness = Via->DrillingHole + MIN_PINORVIACOPPER;
292 Message (_("%m+Increased via thickness to %$mS to allow enough copper"
293 " at %$mD.\n"),
294 Settings.grid_unit->allow, Via->Thickness, Via->X, Via->Y);
297 SetPinBoundingBox (Via);
298 if (!Data->via_tree)
299 Data->via_tree = r_create_tree (NULL, 0, 0);
300 r_insert_entry (Data->via_tree, (BoxTypePtr) Via, 0);
301 return (Via);
304 struct line_info
306 Coord X1, X2, Y1, Y2;
307 Coord Thickness;
308 FlagType Flags;
309 LineType test, *ans;
310 jmp_buf env;
313 static int
314 line_callback (const BoxType * b, void *cl)
316 LineTypePtr line = (LineTypePtr) b;
317 struct line_info *i = (struct line_info *) cl;
319 if (line->Point1.X == i->X1 &&
320 line->Point2.X == i->X2 &&
321 line->Point1.Y == i->Y1 && line->Point2.Y == i->Y2)
323 i->ans = (LineTypePtr) (-1);
324 longjmp (i->env, 1);
326 /* check the other point order */
327 if (line->Point1.X == i->X1 &&
328 line->Point2.X == i->X2 &&
329 line->Point1.Y == i->Y1 && line->Point2.Y == i->Y2)
331 i->ans = (LineTypePtr) (-1);
332 longjmp (i->env, 1);
334 if (line->Point2.X == i->X1 &&
335 line->Point1.X == i->X2 &&
336 line->Point2.Y == i->Y1 && line->Point1.Y == i->Y2)
338 i->ans = (LineTypePtr) - 1;
339 longjmp (i->env, 1);
341 /* remove unnecessary line points */
342 if (line->Thickness == i->Thickness
343 /* don't merge lines if the clear flags differ */
344 && TEST_FLAG (CLEARLINEFLAG, line) == TEST_FLAG (CLEARLINEFLAG, i))
346 if (line->Point1.X == i->X1 && line->Point1.Y == i->Y1)
348 i->test.Point1.X = line->Point2.X;
349 i->test.Point1.Y = line->Point2.Y;
350 i->test.Point2.X = i->X2;
351 i->test.Point2.Y = i->Y2;
352 if (IsPointOnLine (i->X1, i->Y1, 0.0, &i->test))
354 i->ans = line;
355 longjmp (i->env, 1);
358 else if (line->Point2.X == i->X1 && line->Point2.Y == i->Y1)
360 i->test.Point1.X = line->Point1.X;
361 i->test.Point1.Y = line->Point1.Y;
362 i->test.Point2.X = i->X2;
363 i->test.Point2.Y = i->Y2;
364 if (IsPointOnLine (i->X1, i->Y1, 0.0, &i->test))
366 i->ans = line;
367 longjmp (i->env, 1);
370 else if (line->Point1.X == i->X2 && line->Point1.Y == i->Y2)
372 i->test.Point1.X = line->Point2.X;
373 i->test.Point1.Y = line->Point2.Y;
374 i->test.Point2.X = i->X1;
375 i->test.Point2.Y = i->Y1;
376 if (IsPointOnLine (i->X2, i->Y2, 0.0, &i->test))
378 i->ans = line;
379 longjmp (i->env, 1);
382 else if (line->Point2.X == i->X2 && line->Point2.Y == i->Y2)
384 i->test.Point1.X = line->Point1.X;
385 i->test.Point1.Y = line->Point1.Y;
386 i->test.Point2.X = i->X1;
387 i->test.Point2.Y = i->Y1;
388 if (IsPointOnLine (i->X2, i->Y2, 0.0, &i->test))
390 i->ans = line;
391 longjmp (i->env, 1);
395 return 0;
399 /* ---------------------------------------------------------------------------
400 * creates a new line on a layer and checks for overlap and extension
402 LineTypePtr
403 CreateDrawnLineOnLayer (LayerTypePtr Layer,
404 Coord X1, Coord Y1,
405 Coord X2, Coord Y2,
406 Coord Thickness, Coord Clearance,
407 FlagType Flags)
409 struct line_info info;
410 BoxType search;
412 search.X1 = MIN (X1, X2);
413 search.X2 = MAX (X1, X2);
414 search.Y1 = MIN (Y1, Y2);
415 search.Y2 = MAX (Y1, Y2);
416 if (search.Y2 == search.Y1)
417 search.Y2++;
418 if (search.X2 == search.X1)
419 search.X2++;
420 info.X1 = X1;
421 info.X2 = X2;
422 info.Y1 = Y1;
423 info.Y2 = Y2;
424 info.Thickness = Thickness;
425 info.Flags = Flags;
426 info.test.Thickness = 0;
427 info.test.Flags = NoFlags ();
428 info.ans = NULL;
429 /* prevent stacking of duplicate lines
430 * and remove needless intermediate points
431 * verify that the layer is on the board first!
433 if (setjmp (info.env) == 0)
435 r_search (Layer->line_tree, &search, NULL, line_callback, &info);
436 return CreateNewLineOnLayer (Layer, X1, Y1, X2, Y2,
437 Thickness, Clearance, Flags);
440 if ((void *) info.ans == (void *) (-1))
441 return NULL; /* stacked line */
442 /* remove unnecessary points */
443 if (info.ans)
445 /* must do this BEFORE getting new line memory */
446 MoveObjectToRemoveUndoList (LINE_TYPE, Layer, info.ans, info.ans);
447 X1 = info.test.Point1.X;
448 X2 = info.test.Point2.X;
449 Y1 = info.test.Point1.Y;
450 Y2 = info.test.Point2.Y;
452 return CreateNewLineOnLayer (Layer, X1, Y1, X2, Y2,
453 Thickness, Clearance, Flags);
456 LineTypePtr
457 CreateNewLineOnLayer (LayerTypePtr Layer,
458 Coord X1, Coord Y1,
459 Coord X2, Coord Y2,
460 Coord Thickness, Coord Clearance,
461 FlagType Flags)
463 LineTypePtr Line;
465 Line = GetLineMemory (Layer);
466 if (!Line)
467 return (Line);
468 Line->ID = ID++;
469 Line->Flags = Flags;
470 CLEAR_FLAG (RATFLAG, Line);
471 Line->Thickness = Thickness;
472 Line->Clearance = Clearance;
473 Line->Point1.X = X1;
474 Line->Point1.Y = Y1;
475 Line->Point1.ID = ID++;
476 Line->Point2.X = X2;
477 Line->Point2.Y = Y2;
478 Line->Point2.ID = ID++;
479 SetLineBoundingBox (Line);
480 if (!Layer->line_tree)
481 Layer->line_tree = r_create_tree (NULL, 0, 0);
482 r_insert_entry (Layer->line_tree, (BoxTypePtr) Line, 0);
483 return (Line);
486 /* ---------------------------------------------------------------------------
487 * creates a new rat-line
489 RatTypePtr
490 CreateNewRat (DataTypePtr Data, Coord X1, Coord Y1,
491 Coord X2, Coord Y2, Cardinal group1,
492 Cardinal group2, Coord Thickness, FlagType Flags)
494 RatTypePtr Line = GetRatMemory (Data);
496 if (!Line)
497 return (Line);
499 Line->ID = ID++;
500 Line->Flags = Flags;
501 SET_FLAG (RATFLAG, Line);
502 Line->Thickness = Thickness;
503 Line->Point1.X = X1;
504 Line->Point1.Y = Y1;
505 Line->Point1.ID = ID++;
506 Line->Point2.X = X2;
507 Line->Point2.Y = Y2;
508 Line->Point2.ID = ID++;
509 Line->group1 = group1;
510 Line->group2 = group2;
511 SetLineBoundingBox ((LineTypePtr) Line);
512 if (!Data->rat_tree)
513 Data->rat_tree = r_create_tree (NULL, 0, 0);
514 r_insert_entry (Data->rat_tree, &Line->BoundingBox, 0);
515 return (Line);
518 /* ---------------------------------------------------------------------------
519 * creates a new arc on a layer
521 ArcTypePtr
522 CreateNewArcOnLayer (LayerTypePtr Layer,
523 Coord X1, Coord Y1,
524 Coord width,
525 Coord height,
526 Angle sa,
527 Angle dir, Coord Thickness,
528 Coord Clearance, FlagType Flags)
530 ArcTypePtr Arc;
532 ARC_LOOP (Layer);
534 if (arc->X == X1 && arc->Y == Y1 && arc->Width == width &&
535 NormalizeAngle (arc->StartAngle) == NormalizeAngle (sa) &&
536 arc->Delta == dir)
537 return (NULL); /* prevent stacked arcs */
539 END_LOOP;
540 Arc = GetArcMemory (Layer);
541 if (!Arc)
542 return (Arc);
544 Arc->ID = ID++;
545 Arc->Flags = Flags;
546 Arc->Thickness = Thickness;
547 Arc->Clearance = Clearance;
548 Arc->X = X1;
549 Arc->Y = Y1;
550 Arc->Width = width;
551 Arc->Height = height;
552 Arc->StartAngle = sa;
553 Arc->Delta = dir;
554 SetArcBoundingBox (Arc);
555 if (!Layer->arc_tree)
556 Layer->arc_tree = r_create_tree (NULL, 0, 0);
557 r_insert_entry (Layer->arc_tree, (BoxTypePtr) Arc, 0);
558 return (Arc);
562 /* ---------------------------------------------------------------------------
563 * creates a new polygon from the old formats rectangle data
565 PolygonTypePtr
566 CreateNewPolygonFromRectangle (LayerTypePtr Layer,
567 Coord X1, Coord Y1,
568 Coord X2, Coord Y2,
569 FlagType Flags)
571 PolygonTypePtr polygon = CreateNewPolygon (Layer, Flags);
572 if (!polygon)
573 return (polygon);
575 CreateNewPointInPolygon (polygon, X1, Y1);
576 CreateNewPointInPolygon (polygon, X2, Y1);
577 CreateNewPointInPolygon (polygon, X2, Y2);
578 CreateNewPointInPolygon (polygon, X1, Y2);
579 SetPolygonBoundingBox (polygon);
580 if (!Layer->polygon_tree)
581 Layer->polygon_tree = r_create_tree (NULL, 0, 0);
582 r_insert_entry (Layer->polygon_tree, (BoxTypePtr) polygon, 0);
583 return (polygon);
586 /* ---------------------------------------------------------------------------
587 * creates a new text on a layer
589 TextTypePtr
590 CreateNewText (LayerTypePtr Layer, FontTypePtr PCBFont,
591 Coord X, Coord Y,
592 unsigned Direction, int Scale, char *TextString, FlagType Flags)
594 TextType *text;
596 if (TextString == NULL)
597 return NULL;
599 text = GetTextMemory (Layer);
600 if (text == NULL)
601 return NULL;
603 /* copy values, width and height are set by drawing routine
604 * because at this point we don't know which symbols are available
606 text->X = X;
607 text->Y = Y;
608 text->Direction = Direction;
609 text->Flags = Flags;
610 text->Scale = Scale;
611 text->TextString = strdup (TextString);
613 /* calculate size of the bounding box */
614 SetTextBoundingBox (PCBFont, text);
615 text->ID = ID++;
616 if (!Layer->text_tree)
617 Layer->text_tree = r_create_tree (NULL, 0, 0);
618 r_insert_entry (Layer->text_tree, (BoxTypePtr) text, 0);
619 return (text);
622 /* ---------------------------------------------------------------------------
623 * creates a new polygon on a layer
625 PolygonTypePtr
626 CreateNewPolygon (LayerTypePtr Layer, FlagType Flags)
628 PolygonTypePtr polygon = GetPolygonMemory (Layer);
630 /* copy values */
631 polygon->Flags = Flags;
632 polygon->ID = ID++;
633 polygon->Clipped = NULL;
634 polygon->NoHoles = NULL;
635 polygon->NoHolesValid = 0;
636 return (polygon);
639 /* ---------------------------------------------------------------------------
640 * creates a new point in a polygon
642 PointTypePtr
643 CreateNewPointInPolygon (PolygonTypePtr Polygon, Coord X, Coord Y)
645 PointTypePtr point = GetPointMemoryInPolygon (Polygon);
647 /* copy values */
648 point->X = X;
649 point->Y = Y;
650 point->ID = ID++;
651 return (point);
654 /* ---------------------------------------------------------------------------
655 * creates a new hole in a polygon
657 PolygonType *
658 CreateNewHoleInPolygon (PolygonType *Polygon)
660 Cardinal *holeindex = GetHoleIndexMemoryInPolygon (Polygon);
661 *holeindex = Polygon->PointN;
662 return Polygon;
665 /* ---------------------------------------------------------------------------
666 * creates an new element
667 * memory is allocated if needed
669 ElementTypePtr
670 CreateNewElement (DataTypePtr Data, ElementTypePtr Element,
671 FontTypePtr PCBFont,
672 FlagType Flags,
673 char *Description, char *NameOnPCB, char *Value,
674 Coord TextX, Coord TextY, BYTE Direction,
675 int TextScale, FlagType TextFlags, bool uniqueName)
677 #ifdef DEBUG
678 printf("Entered CreateNewElement.....\n");
679 #endif
681 if (!Element)
682 Element = GetElementMemory (Data);
684 /* copy values and set additional information */
685 TextScale = MAX (MIN_TEXTSCALE, TextScale);
686 AddTextToElement (&DESCRIPTION_TEXT (Element), PCBFont, TextX, TextY,
687 Direction, Description, TextScale, TextFlags);
688 if (uniqueName)
689 NameOnPCB = UniqueElementName (Data, NameOnPCB);
690 AddTextToElement (&NAMEONPCB_TEXT (Element), PCBFont, TextX, TextY,
691 Direction, NameOnPCB, TextScale, TextFlags);
692 AddTextToElement (&VALUE_TEXT (Element), PCBFont, TextX, TextY,
693 Direction, Value, TextScale, TextFlags);
694 DESCRIPTION_TEXT (Element).Element = Element;
695 NAMEONPCB_TEXT (Element).Element = Element;
696 VALUE_TEXT (Element).Element = Element;
697 Element->Flags = Flags;
698 Element->ID = ID++;
700 #ifdef DEBUG
701 printf(" .... Leaving CreateNewElement.\n");
702 #endif
704 return (Element);
707 /* ---------------------------------------------------------------------------
708 * creates a new arc in an element
710 ArcTypePtr
711 CreateNewArcInElement (ElementTypePtr Element,
712 Coord X, Coord Y,
713 Coord Width, Coord Height,
714 Angle angle, Angle delta, Coord Thickness)
716 ArcType *arc;
718 arc = g_slice_new0 (ArcType);
719 Element->Arc = g_list_append (Element->Arc, arc);
720 Element->ArcN ++;
722 /* set Delta (0,360], StartAngle in [0,360) */
723 if (delta < 0)
725 delta = -delta;
726 angle -= delta;
728 angle = NormalizeAngle (angle);
729 delta = NormalizeAngle (delta);
730 if (delta == 0)
731 delta = 360;
733 /* copy values */
734 arc->X = X;
735 arc->Y = Y;
736 arc->Width = Width;
737 arc->Height = Height;
738 arc->StartAngle = angle;
739 arc->Delta = delta;
740 arc->Thickness = Thickness;
741 arc->ID = ID++;
742 return arc;
745 /* ---------------------------------------------------------------------------
746 * creates a new line for an element
748 LineTypePtr
749 CreateNewLineInElement (ElementTypePtr Element,
750 Coord X1, Coord Y1,
751 Coord X2, Coord Y2,
752 Coord Thickness)
754 LineType *line;
756 if (Thickness == 0)
757 return NULL;
759 line = g_slice_new0 (LineType);
760 Element->Line = g_list_append (Element->Line, line);
761 Element->LineN ++;
763 /* copy values */
764 line->Point1.X = X1;
765 line->Point1.Y = Y1;
766 line->Point2.X = X2;
767 line->Point2.Y = Y2;
768 line->Thickness = Thickness;
769 line->Flags = NoFlags ();
770 line->ID = ID++;
771 return line;
774 /* ---------------------------------------------------------------------------
775 * creates a new pin in an element
777 PinTypePtr
778 CreateNewPin (ElementTypePtr Element,
779 Coord X, Coord Y,
780 Coord Thickness, Coord Clearance, Coord Mask,
781 Coord DrillingHole, char *Name, char *Number,
782 FlagType Flags)
784 PinTypePtr pin = GetPinMemory (Element);
786 /* copy values */
787 pin->X = X;
788 pin->Y = Y;
789 pin->Thickness = Thickness;
790 pin->Clearance = Clearance;
791 pin->Mask = Mask;
792 pin->Name = STRDUP (Name);
793 pin->Number = STRDUP (Number);
794 pin->Flags = Flags;
795 CLEAR_FLAG (WARNFLAG, pin);
796 SET_FLAG (PINFLAG, pin);
797 pin->ID = ID++;
798 pin->Element = Element;
801 * If there is no vendor drill map installed, this will simply
802 * return DrillingHole.
804 pin->DrillingHole = vendorDrillMap (DrillingHole);
806 /* Unless we should not map drills on this element, map them! */
807 if (vendorIsElementMappable (Element))
809 if (pin->DrillingHole < MIN_PINORVIASIZE)
811 Message (_("%m+Did not map pin #%s (%s) drill hole because %$mS is below the minimum allowed size\n"),
812 Settings.grid_unit->allow, UNKNOWN (Number), UNKNOWN (Name), pin->DrillingHole);
813 pin->DrillingHole = DrillingHole;
815 else if (pin->DrillingHole > MAX_PINORVIASIZE)
817 Message (_("%m+Did not map pin #%s (%s) drill hole because %$mS is above the maximum allowed size\n"),
818 Settings.grid_unit->allow, UNKNOWN (Number), UNKNOWN (Name), pin->DrillingHole);
819 pin->DrillingHole = DrillingHole;
821 else if (!TEST_FLAG (HOLEFLAG, pin)
822 && (pin->DrillingHole > pin->Thickness - MIN_PINORVIACOPPER))
824 Message (_("%m+Did not map pin #%s (%s) drill hole because %$mS does not leave enough copper\n"),
825 Settings.grid_unit->allow, UNKNOWN (Number), UNKNOWN (Name), pin->DrillingHole);
826 pin->DrillingHole = DrillingHole;
829 else
831 pin->DrillingHole = DrillingHole;
834 if (pin->DrillingHole != DrillingHole)
836 Message (_("%m+Mapped pin drill hole to %$mS from %$mS per vendor table\n"),
837 Settings.grid_unit->allow, pin->DrillingHole, DrillingHole);
840 return (pin);
843 /* ---------------------------------------------------------------------------
844 * creates a new pad in an element
846 PadTypePtr
847 CreateNewPad (ElementTypePtr Element,
848 Coord X1, Coord Y1, Coord X2,
849 Coord Y2, Coord Thickness, Coord Clearance,
850 Coord Mask, char *Name, char *Number, FlagType Flags)
852 PadTypePtr pad = GetPadMemory (Element);
854 /* copy values */
855 if (X1 > X2 || (X1 == X2 && Y1 > Y2))
857 pad->Point1.X = X2;
858 pad->Point1.Y = Y2;
859 pad->Point2.X = X1;
860 pad->Point2.Y = Y1;
862 else
864 pad->Point1.X = X1;
865 pad->Point1.Y = Y1;
866 pad->Point2.X = X2;
867 pad->Point2.Y = Y2;
869 pad->Thickness = Thickness;
870 pad->Clearance = Clearance;
871 pad->Mask = Mask;
872 pad->Name = STRDUP (Name);
873 pad->Number = STRDUP (Number);
874 pad->Flags = Flags;
875 CLEAR_FLAG (WARNFLAG, pad);
876 pad->ID = ID++;
877 pad->Element = Element;
878 return (pad);
881 /* ---------------------------------------------------------------------------
882 * creates a new textobject as part of an element
883 * copies the values to the appropriate text object
885 static void
886 AddTextToElement (TextTypePtr Text, FontTypePtr PCBFont,
887 Coord X, Coord Y,
888 unsigned Direction, char *TextString, int Scale, FlagType Flags)
890 free (Text->TextString);
891 Text->TextString = (TextString && *TextString) ? strdup (TextString) : NULL;
892 Text->X = X;
893 Text->Y = Y;
894 Text->Direction = Direction;
895 Text->Flags = Flags;
896 Text->Scale = Scale;
898 /* calculate size of the bounding box */
899 SetTextBoundingBox (PCBFont, Text);
900 Text->ID = ID++;
903 /* ---------------------------------------------------------------------------
904 * creates a new line in a symbol
906 LineTypePtr
907 CreateNewLineInSymbol (SymbolTypePtr Symbol,
908 Coord X1, Coord Y1,
909 Coord X2, Coord Y2, Coord Thickness)
911 LineTypePtr line = Symbol->Line;
913 /* realloc new memory if necessary and clear it */
914 if (Symbol->LineN >= Symbol->LineMax)
916 Symbol->LineMax += STEP_SYMBOLLINE;
917 line = (LineTypePtr)realloc (line, Symbol->LineMax * sizeof (LineType));
918 Symbol->Line = line;
919 memset (line + Symbol->LineN, 0, STEP_SYMBOLLINE * sizeof (LineType));
922 /* copy values */
923 line = line + Symbol->LineN++;
924 line->Point1.X = X1;
925 line->Point1.Y = Y1;
926 line->Point2.X = X2;
927 line->Point2.Y = Y2;
928 line->Thickness = Thickness;
929 return (line);
932 /* ---------------------------------------------------------------------------
933 * parses a file with font information and installs it into the provided PCB
934 * checks directories given as colon separated list by resource fontPath
935 * if the fonts filename doesn't contain a directory component
937 void
938 CreateDefaultFont (PCBTypePtr pcb)
940 if (ParseFont (&pcb->Font, Settings.FontFile))
941 Message (_("Can't find font-symbol-file '%s'\n"), Settings.FontFile);
944 /* ---------------------------------------------------------------------------
945 * adds a new line to the rubberband list of 'Crosshair.AttachedObject'
946 * if Layer == 0 it is a rat line
948 RubberbandTypePtr
949 CreateNewRubberbandEntry (LayerTypePtr Layer,
950 LineTypePtr Line, PointTypePtr MovedPoint)
952 RubberbandTypePtr ptr = GetRubberbandMemory ();
954 /* we toggle the RUBBERENDFLAG of the line to determine if */
955 /* both points are being moved. */
956 TOGGLE_FLAG (RUBBERENDFLAG, Line);
957 ptr->Layer = Layer;
958 ptr->Line = Line;
959 ptr->MovedPoint = MovedPoint;
960 return (ptr);
963 /* ---------------------------------------------------------------------------
964 * Add a new net to the netlist menu
966 LibraryMenuTypePtr
967 CreateNewNet (LibraryTypePtr lib, char *name, char *style)
969 LibraryMenuTypePtr menu;
970 char temp[64];
972 sprintf (temp, " %s", name);
973 menu = GetLibraryMenuMemory (lib);
974 menu->Name = strdup (temp);
975 menu->flag = 1; /* net is enabled by default */
976 if (style == NULL || NSTRCMP ("(unknown)", style) == 0)
977 menu->Style = NULL;
978 else
979 menu->Style = strdup (style);
980 return (menu);
983 /* ---------------------------------------------------------------------------
984 * Add a connection to the net
986 LibraryEntryTypePtr
987 CreateNewConnection (LibraryMenuTypePtr net, char *conn)
989 LibraryEntryTypePtr entry = GetLibraryEntryMemory (net);
991 entry->ListEntry = STRDUP (conn);
992 return (entry);
995 /* ---------------------------------------------------------------------------
996 * Add an attribute to a list.
998 AttributeTypePtr
999 CreateNewAttribute (AttributeListTypePtr list, char *name, char *value)
1001 if (list->Number >= list->Max)
1003 list->Max += 10;
1004 list->List = (AttributeType *)realloc (list->List, list->Max * sizeof (AttributeType));
1006 list->List[list->Number].name = STRDUP (name);
1007 list->List[list->Number].value = STRDUP (value);
1008 list->Number++;
1009 return &list->List[list->Number - 1];