(no commit message)
[geda-pcb/pcjc2.git] / src / create.c
blobf01c118a7f3d21bf144655117241c7f0e9665cf3
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
27 /* functions used to create vias, pins ...
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
34 #include <assert.h>
35 #include <memory.h>
36 #include <setjmp.h>
37 #include <stdlib.h>
39 #include "global.h"
41 #include "create.h"
42 #include "data.h"
43 #include "draw.h"
44 #include "error.h"
45 #include "mymem.h"
46 #include "misc.h"
47 #include "parse_l.h"
48 #include "pcb-printf.h"
49 #include "polygon.h"
50 #include "rtree.h"
51 #include "search.h"
52 #include "set.h"
53 #include "undo.h"
54 #include "vendor.h"
56 #ifdef HAVE_LIBDMALLOC
57 #include <dmalloc.h>
58 #endif
60 /* ---------------------------------------------------------------------------
61 * some local identifiers
63 static int ID = 1; /* current object ID; incremented after */
64 /* each creation of an object */
66 static bool be_lenient = false;
68 /* ----------------------------------------------------------------------
69 * some local prototypes
71 static void AddTextToElement (TextType *, FontType *,
72 Coord, Coord, unsigned, char *, int,
73 FlagType);
75 /* ---------------------------------------------------------------------------
76 * Set the lenience mode.
79 void
80 CreateBeLenient (bool v)
82 be_lenient = v;
85 /* ---------------------------------------------------------------------------
86 * creates a new paste buffer
88 DataType *
89 CreateNewBuffer (void)
91 DataType *data;
92 data = (DataType *) calloc (1, sizeof (DataType));
93 data->pcb = (PCBType *) PCB;
94 return data;
97 /* ---------------------------------------------------------------------------
98 * Perhaps PCB should internally just use the Settings colors? For now,
99 * use this to set PCB colors so the config can reassign PCB colors.
101 void
102 pcb_colors_from_settings (PCBType *ptr)
104 int i;
106 /* copy default settings */
107 ptr->ConnectedColor = Settings.ConnectedColor;
108 ptr->FoundColor = Settings.FoundColor;
109 ptr->ElementColor = Settings.ElementColor;
110 ptr->RatColor = Settings.RatColor;
111 ptr->InvisibleObjectsColor = Settings.InvisibleObjectsColor;
112 ptr->InvisibleMarkColor = Settings.InvisibleMarkColor;
113 ptr->ElementSelectedColor = Settings.ElementSelectedColor;
114 ptr->RatSelectedColor = Settings.RatSelectedColor;
115 ptr->PinColor = Settings.PinColor;
116 ptr->PinSelectedColor = Settings.PinSelectedColor;
117 ptr->PinNameColor = Settings.PinNameColor;
118 ptr->ViaColor = Settings.ViaColor;
119 ptr->ViaSelectedColor = Settings.ViaSelectedColor;
120 ptr->WarnColor = Settings.WarnColor;
121 ptr->MaskColor = Settings.MaskColor;
122 for (i = 0; i < MAX_LAYER; i++)
124 ptr->Data->Layer[i].Color = Settings.LayerColor[i];
125 ptr->Data->Layer[i].SelectedColor = Settings.LayerSelectedColor[i];
127 ptr->Data->Layer[top_silk_layer].Color =
128 Settings.ShowBottomSide ?
129 Settings.InvisibleObjectsColor : Settings.ElementColor;
130 ptr->Data->Layer[top_silk_layer].SelectedColor =
131 Settings.ElementSelectedColor;
132 ptr->Data->Layer[bottom_silk_layer].Color =
133 Settings.ShowBottomSide ?
134 Settings.ElementColor : Settings.InvisibleObjectsColor;
135 ptr->Data->Layer[bottom_silk_layer].SelectedColor =
136 Settings.ElementSelectedColor;
139 /* ---------------------------------------------------------------------------
140 * creates a new PCB
142 PCBType *
143 CreateNewPCB (bool SetDefaultNames)
145 PCBType *ptr;
146 int i;
148 /* allocate memory, switch all layers on and copy resources */
149 ptr = (PCBType *)calloc (1, sizeof (PCBType));
150 ptr->Data = CreateNewBuffer ();
151 ptr->Data->pcb = (PCBType *) ptr;
152 ptr->Data->polyClip = 1;
154 ptr->ThermStyle = 4;
155 ptr->IsleArea = 2.e8;
156 ptr->SilkActive = false;
157 ptr->RatDraw = false;
158 SET_FLAG (NAMEONPCBFLAG, ptr);
159 if (Settings.ShowNumber)
160 SET_FLAG (SHOWNUMBERFLAG, ptr);
161 if (Settings.AllDirectionLines)
162 SET_FLAG (ALLDIRECTIONFLAG, ptr);
163 ptr->Clipping = 1; /* this is the most useful starting point for now */
164 if (Settings.RubberBandMode)
165 SET_FLAG (RUBBERBANDFLAG, ptr);
166 if (Settings.SwapStartDirection)
167 SET_FLAG (SWAPSTARTDIRFLAG, ptr);
168 if (Settings.UniqueNames)
169 SET_FLAG (UNIQUENAMEFLAG, ptr);
170 if (Settings.SnapPin)
171 SET_FLAG (SNAPPINFLAG, ptr);
172 if (Settings.ClearLine)
173 SET_FLAG (CLEARNEWFLAG, ptr);
174 if (Settings.FullPoly)
175 SET_FLAG (NEWFULLPOLYFLAG, ptr);
176 if (Settings.OrthogonalMoves)
177 SET_FLAG (ORTHOMOVEFLAG, ptr);
178 if (Settings.liveRouting)
179 SET_FLAG (LIVEROUTEFLAG, ptr);
180 if (Settings.ShowDRC)
181 SET_FLAG (SHOWDRCFLAG, ptr);
182 if (Settings.AutoDRC)
183 SET_FLAG (AUTODRCFLAG, ptr);
184 ptr->Grid = Settings.Grid;
185 ptr->LayerGroups = Settings.LayerGroups;
186 STYLE_LOOP (ptr);
188 *style = Settings.RouteStyle[n];
189 style->index = n;
191 END_LOOP;
192 ptr->MaxWidth = Settings.MaxWidth;
193 ptr->MaxHeight = Settings.MaxHeight;
194 ptr->ID = ID++;
195 ptr->ThermScale = 0.5;
197 ptr->Bloat = Settings.Bloat;
198 ptr->Shrink = Settings.Shrink;
199 ptr->minWid = Settings.minWid;
200 ptr->minSlk = Settings.minSlk;
201 ptr->minDrill = Settings.minDrill;
202 ptr->minRing = Settings.minRing;
204 for (i = 0; i < MAX_LAYER; i++)
205 ptr->Data->Layer[i].Name = strdup (Settings.DefaultLayerName[i]);
207 CreateDefaultFont (ptr);
209 return (ptr);
212 /* This post-processing step adds the top and bottom silk layers to a
213 * pre-existing PCB.
216 CreateNewPCBPost (PCBType *pcb, int use_defaults)
218 /* copy default settings */
219 pcb_colors_from_settings (pcb);
221 if (use_defaults)
223 if (ParseGroupString (Settings.Groups, &pcb->LayerGroups, &pcb->Data->LayerN))
224 return 1;
226 pcb->Data->Layer[top_silk_layer].Name = strdup ("silk");
227 pcb->Data->Layer[bottom_silk_layer].Name = strdup ("silk");
229 return 0;
232 /* ---------------------------------------------------------------------------
233 * creates a new via
235 PinType *
236 CreateNewVia (DataType *Data,
237 Coord X, Coord Y,
238 Coord Thickness, Coord Clearance, Coord Mask,
239 Coord DrillingHole, char *Name, FlagType Flags)
241 PinType *Via;
243 if (!be_lenient)
245 VIA_LOOP (Data);
247 if (Distance (X, Y, via->X, via->Y) <=
248 via->DrillingHole / 2 + DrillingHole / 2)
250 Message (_("%m+Dropping via at %$mD because it's hole would overlap with the via "
251 "at %$mD\n"), Settings.grid_unit->allow, X, Y, via->X, via->Y);
252 return (NULL); /* don't allow via stacking */
255 END_LOOP;
258 Via = GetViaMemory (Data);
260 if (!Via)
261 return (Via);
262 /* copy values */
263 Via->X = X;
264 Via->Y = Y;
265 Via->Thickness = Thickness;
266 Via->Clearance = Clearance;
267 Via->Mask = Mask;
268 Via->DrillingHole = vendorDrillMap (DrillingHole);
269 if (Via->DrillingHole != DrillingHole)
271 Message (_("%m+Mapped via drill hole to %$mS from %$mS per vendor table\n"),
272 Settings.grid_unit->allow, Via->DrillingHole, DrillingHole);
275 Via->Name = STRDUP (Name);
276 Via->Flags = Flags;
277 CLEAR_FLAG (WARNFLAG, Via);
278 SET_FLAG (VIAFLAG, Via);
279 Via->ID = ID++;
282 * don't complain about MIN_PINORVIACOPPER on a mounting hole (pure
283 * hole)
285 if (!TEST_FLAG (HOLEFLAG, Via) &&
286 (Via->Thickness < Via->DrillingHole + MIN_PINORVIACOPPER))
288 Via->Thickness = Via->DrillingHole + MIN_PINORVIACOPPER;
289 Message (_("%m+Increased via thickness to %$mS to allow enough copper"
290 " at %$mD.\n"),
291 Settings.grid_unit->allow, Via->Thickness, Via->X, Via->Y);
294 SetPinBoundingBox (Via);
295 if (!Data->via_tree)
296 Data->via_tree = r_create_tree (NULL, 0, 0);
297 r_insert_entry (Data->via_tree, (BoxType *) Via, 0);
298 return (Via);
301 struct line_info
303 Coord X1, X2, Y1, Y2;
304 Coord Thickness;
305 Coord Clearance;
306 FlagType Flags;
307 LineType test, *ans;
308 jmp_buf env;
311 static int
312 line_callback (const BoxType * b, void *cl)
314 LineType *line = (LineType *) b;
315 struct line_info *i = (struct line_info *) cl;
317 if (line->Point1.X == i->X1 &&
318 line->Point2.X == i->X2 &&
319 line->Point1.Y == i->Y1 && line->Point2.Y == i->Y2)
321 i->ans = (LineType *) (-1);
322 longjmp (i->env, 1);
324 /* check the other point order */
325 if (line->Point1.X == i->X1 &&
326 line->Point2.X == i->X2 &&
327 line->Point1.Y == i->Y1 && line->Point2.Y == i->Y2)
329 i->ans = (LineType *) (-1);
330 longjmp (i->env, 1);
332 if (line->Point2.X == i->X1 &&
333 line->Point1.X == i->X2 &&
334 line->Point2.Y == i->Y1 && line->Point1.Y == i->Y2)
336 i->ans = (LineType *) - 1;
337 longjmp (i->env, 1);
339 /* remove unnecessary line points */
340 if (line->Thickness == i->Thickness &&
341 /* don't merge lines if the clearances differ */
342 line->Clearance == i->Clearance &&
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 LineType *
403 CreateDrawnLineOnLayer (LayerType *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.Clearance = Clearance;
426 info.Flags = Flags;
427 info.test.Thickness = 0;
428 info.test.Flags = NoFlags ();
429 info.ans = NULL;
430 /* prevent stacking of duplicate lines
431 * and remove needless intermediate points
432 * verify that the layer is on the board first!
434 if (setjmp (info.env) == 0)
436 r_search (Layer->line_tree, &search, NULL, line_callback, &info);
437 return CreateNewLineOnLayer (Layer, X1, Y1, X2, Y2,
438 Thickness, Clearance, Flags);
441 if ((void *) info.ans == (void *) (-1))
442 return NULL; /* stacked line */
443 /* remove unnecessary points */
444 if (info.ans)
446 /* must do this BEFORE getting new line memory */
447 MoveObjectToRemoveUndoList (LINE_TYPE, Layer, info.ans, info.ans);
448 X1 = info.test.Point1.X;
449 X2 = info.test.Point2.X;
450 Y1 = info.test.Point1.Y;
451 Y2 = info.test.Point2.Y;
453 return CreateNewLineOnLayer (Layer, X1, Y1, X2, Y2,
454 Thickness, Clearance, Flags);
457 LineType *
458 CreateNewLineOnLayer (LayerType *Layer,
459 Coord X1, Coord Y1,
460 Coord X2, Coord Y2,
461 Coord Thickness, Coord Clearance,
462 FlagType Flags)
464 LineType *Line;
466 Line = GetLineMemory (Layer);
467 if (!Line)
468 return (Line);
469 Line->ID = ID++;
470 Line->Flags = Flags;
471 CLEAR_FLAG (RATFLAG, Line);
472 Line->Thickness = Thickness;
473 Line->Clearance = Clearance;
474 Line->Point1.X = X1;
475 Line->Point1.Y = Y1;
476 Line->Point1.ID = ID++;
477 Line->Point2.X = X2;
478 Line->Point2.Y = Y2;
479 Line->Point2.ID = ID++;
480 SetLineBoundingBox (Line);
481 if (!Layer->line_tree)
482 Layer->line_tree = r_create_tree (NULL, 0, 0);
483 r_insert_entry (Layer->line_tree, (BoxType *) Line, 0);
484 return (Line);
487 /* ---------------------------------------------------------------------------
488 * creates a new rat-line
490 RatType *
491 CreateNewRat (DataType *Data, Coord X1, Coord Y1,
492 Coord X2, Coord Y2, Cardinal group1,
493 Cardinal group2, Coord Thickness, FlagType Flags)
495 RatType *Line = GetRatMemory (Data);
497 if (!Line)
498 return (Line);
500 Line->ID = ID++;
501 Line->Flags = Flags;
502 SET_FLAG (RATFLAG, Line);
503 Line->Thickness = Thickness;
504 Line->Point1.X = X1;
505 Line->Point1.Y = Y1;
506 Line->Point1.ID = ID++;
507 Line->Point2.X = X2;
508 Line->Point2.Y = Y2;
509 Line->Point2.ID = ID++;
510 Line->group1 = group1;
511 Line->group2 = group2;
512 SetLineBoundingBox ((LineType *) Line);
513 if (!Data->rat_tree)
514 Data->rat_tree = r_create_tree (NULL, 0, 0);
515 r_insert_entry (Data->rat_tree, &Line->BoundingBox, 0);
516 return (Line);
519 /* ---------------------------------------------------------------------------
520 * creates a new arc on a layer
522 ArcType *
523 CreateNewArcOnLayer (LayerType *Layer,
524 Coord X1, Coord Y1,
525 Coord width,
526 Coord height,
527 Angle sa,
528 Angle dir, Coord Thickness,
529 Coord Clearance, FlagType Flags)
531 ArcType *Arc;
533 ARC_LOOP (Layer);
535 if (arc->X == X1 && arc->Y == Y1 && arc->Width == width &&
536 NormalizeAngle (arc->StartAngle) == NormalizeAngle (sa) &&
537 arc->Delta == dir)
538 return (NULL); /* prevent stacked arcs */
540 END_LOOP;
541 Arc = GetArcMemory (Layer);
542 if (!Arc)
543 return (Arc);
545 Arc->ID = ID++;
546 Arc->Flags = Flags;
547 Arc->Thickness = Thickness;
548 Arc->Clearance = Clearance;
549 Arc->X = X1;
550 Arc->Y = Y1;
551 Arc->Width = width;
552 Arc->Height = height;
553 Arc->StartAngle = sa;
554 Arc->Delta = dir;
555 SetArcBoundingBox (Arc);
556 if (!Layer->arc_tree)
557 Layer->arc_tree = r_create_tree (NULL, 0, 0);
558 r_insert_entry (Layer->arc_tree, (BoxType *) Arc, 0);
559 return (Arc);
563 /* ---------------------------------------------------------------------------
564 * creates a new polygon from the old formats rectangle data
566 PolygonType *
567 CreateNewPolygonFromRectangle (LayerType *Layer,
568 Coord X1, Coord Y1,
569 Coord X2, Coord Y2,
570 FlagType Flags)
572 PolygonType *polygon = CreateNewPolygon (Layer, Flags);
573 if (!polygon)
574 return (polygon);
576 CreateNewPointInPolygon (polygon, X1, Y1);
577 CreateNewPointInPolygon (polygon, X2, Y1);
578 CreateNewPointInPolygon (polygon, X2, Y2);
579 CreateNewPointInPolygon (polygon, X1, Y2);
580 SetPolygonBoundingBox (polygon);
581 if (!Layer->polygon_tree)
582 Layer->polygon_tree = r_create_tree (NULL, 0, 0);
583 r_insert_entry (Layer->polygon_tree, (BoxType *) polygon, 0);
584 return (polygon);
587 /* ---------------------------------------------------------------------------
588 * creates a new text on a layer
590 TextType *
591 CreateNewText (LayerType *Layer, FontType *PCBFont,
592 Coord X, Coord Y,
593 unsigned Direction, int Scale, char *TextString, FlagType Flags)
595 TextType *text;
597 if (TextString == NULL)
598 return NULL;
600 text = GetTextMemory (Layer);
601 if (text == NULL)
602 return NULL;
604 /* copy values, width and height are set by drawing routine
605 * because at this point we don't know which symbols are available
607 text->X = X;
608 text->Y = Y;
609 text->Direction = Direction;
610 text->Flags = Flags;
611 text->Scale = Scale;
612 text->TextString = strdup (TextString);
614 /* calculate size of the bounding box */
615 SetTextBoundingBox (PCBFont, text);
616 text->ID = ID++;
617 if (!Layer->text_tree)
618 Layer->text_tree = r_create_tree (NULL, 0, 0);
619 r_insert_entry (Layer->text_tree, (BoxType *) text, 0);
620 return (text);
623 /* ---------------------------------------------------------------------------
624 * creates a new polygon on a layer
626 PolygonType *
627 CreateNewPolygon (LayerType *Layer, FlagType Flags)
629 PolygonType *polygon = GetPolygonMemory (Layer);
631 /* copy values */
632 polygon->Flags = Flags;
633 polygon->ID = ID++;
634 polygon->Clipped = NULL;
635 polygon->NoHoles = NULL;
636 polygon->NoHolesValid = 0;
637 return (polygon);
640 /* ---------------------------------------------------------------------------
641 * creates a new point in a polygon
643 PointType *
644 CreateNewPointInPolygon (PolygonType *Polygon, Coord X, Coord Y)
646 PointType *point = GetPointMemoryInPolygon (Polygon);
648 /* copy values */
649 point->X = X;
650 point->Y = Y;
651 point->ID = ID++;
652 return (point);
655 /* ---------------------------------------------------------------------------
656 * creates a new hole in a polygon
658 PolygonType *
659 CreateNewHoleInPolygon (PolygonType *Polygon)
661 Cardinal *holeindex = GetHoleIndexMemoryInPolygon (Polygon);
662 *holeindex = Polygon->PointN;
663 return Polygon;
666 /* ---------------------------------------------------------------------------
667 * creates an new element
668 * memory is allocated if needed
670 ElementType *
671 CreateNewElement (DataType *Data, FontType *PCBFont, FlagType Flags,
672 char *Description, char *NameOnPCB, char *Value,
673 Coord TextX, Coord TextY, BYTE Direction,
674 int TextScale, FlagType TextFlags, bool uniqueName)
676 ElementType *Element;
678 #ifdef DEBUG
679 printf("Entered CreateNewElement.....\n");
680 #endif
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 ArcType *
711 CreateNewArcInElement (ElementType *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 LineType *
749 CreateNewLineInElement (ElementType *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 PinType *
778 CreateNewPin (ElementType *Element,
779 Coord X, Coord Y,
780 Coord Thickness, Coord Clearance, Coord Mask,
781 Coord DrillingHole, char *Name, char *Number,
782 FlagType Flags)
784 PinType *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 PadType *
847 CreateNewPad (ElementType *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 PadType *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 (TextType *Text, FontType *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 LineType *
907 CreateNewLineInSymbol (SymbolType *Symbol,
908 Coord X1, Coord Y1,
909 Coord X2, Coord Y2, Coord Thickness)
911 LineType *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 = (LineType *)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 (PCBType *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 RubberbandType *
949 CreateNewRubberbandEntry (LayerType *Layer,
950 LineType *Line, PointType *MovedPoint)
952 RubberbandType *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 LibraryMenuType *
967 CreateNewNet (LibraryType *lib, char *name, char *style)
969 LibraryMenuType *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 LibraryEntryType *
987 CreateNewConnection (LibraryMenuType *net, char *conn)
989 LibraryEntryType *entry = GetLibraryEntryMemory (net);
991 entry->ListEntry = STRDUP (conn);
992 return (entry);
995 /* ---------------------------------------------------------------------------
996 * Add an attribute to a list.
998 AttributeType *
999 CreateNewAttribute (AttributeListType *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];