1 /*!
2  * \file src/create.c
3  *
4  * \brief Functions used to create vias, pins ...
5  *
6  * <hr>
7  *
8  * <h1><b>Copyright.</b></h1>\n
9  *
10  * PCB, interactive printed circuit board design
11  *
12  * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27  *
28  * Contact addresses for paper mail and Email:
29  * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
30  * Thomas.Nau@rz.uni-ulm.de
31  */
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include <assert.h>
38 #include <memory.h>
39 #include <setjmp.h>
40 #include <stdlib.h>
41 
42 #include "global.h"
43 
44 #include "create.h"
45 #include "data.h"
46 #include "draw.h"
47 #include "error.h"
48 #include "hid.h" /* REGISTER_ACTIONS */
49 #include "mymem.h"
50 #include "misc.h"
51 #include "parse_l.h"
52 #include "pcb-printf.h"
53 #include "polygon.h"
54 #include "rtree.h"
55 #include "search.h"
56 #include "set.h"
57 #include "undo.h"
58 #include "vendor.h"
59 
60 #ifdef HAVE_LIBDMALLOC
61 #include <dmalloc.h>
62 #endif
63 
64 /* ---------------------------------------------------------------------------
65  * some local identifiers
66  */
67 static long int ID = 1;
68   /*!< Current object ID; incremented after each creation of an object */
69 
70 static bool be_lenient = false;
71 
72 /* ----------------------------------------------------------------------
73  * some local prototypes
74  */
75 static void AddTextToElement (TextType *, FontType *,
76 			      Coord, Coord, unsigned, char *, int,
77 			      FlagType);
78 
79 /*!
80  * \brief Set the lenience mode.
81  *
82  * \c TRUE during file loads, for example to allow overlapping vias.\n
83  * \c FALSE otherwise, to stop the user from doing normally dangerous
84  * things.
85  */
86 void
CreateBeLenient(bool v)87 CreateBeLenient (bool v)
88 {
89   be_lenient = v;
90 }
91 
92 /*!
93  * \brief Creates a new paste buffer.
94  */
95 DataType *
CreateNewBuffer(void)96 CreateNewBuffer (void)
97 {
98   DataType *data;
99   data = (DataType *) calloc (1, sizeof (DataType));
100   data->pcb = (PCBType *) PCB;
101   return data;
102 }
103 
104 /*!
105  * \brief Perhaps PCB should internally just use the Settings colors?
106  *
107  * For now, use this to set PCB colors so the config can reassign PCB
108  * colors.
109  */
110 void
pcb_colors_from_settings(PCBType * ptr)111 pcb_colors_from_settings (PCBType *ptr)
112 {
113   int i;
114 
115   /* copy default settings */
116   ptr->ConnectedColor = Settings.ConnectedColor;
117   ptr->FoundColor = Settings.FoundColor;
118   ptr->ElementColor = Settings.ElementColor;
119   ptr->RatColor = Settings.RatColor;
120   ptr->InvisibleObjectsColor = Settings.InvisibleObjectsColor;
121   ptr->InvisibleMarkColor = Settings.InvisibleMarkColor;
122   ptr->ElementSelectedColor = Settings.ElementSelectedColor;
123   ptr->RatSelectedColor = Settings.RatSelectedColor;
124   ptr->PinColor = Settings.PinColor;
125   ptr->PinSelectedColor = Settings.PinSelectedColor;
126   ptr->PinNameColor = Settings.PinNameColor;
127   ptr->ViaColor = Settings.ViaColor;
128   ptr->ViaSelectedColor = Settings.ViaSelectedColor;
129   ptr->WarnColor = Settings.WarnColor;
130   ptr->MaskColor = Settings.MaskColor;
131   for (i = 0; i < MAX_LAYER; i++)
132     {
133       ptr->Data->Layer[i].Color = Settings.LayerColor[i];
134       ptr->Data->Layer[i].SelectedColor = Settings.LayerSelectedColor[i];
135     }
136   ptr->Data->Layer[top_silk_layer].Color =
137     Settings.ShowBottomSide ?
138     Settings.InvisibleObjectsColor : Settings.ElementColor;
139   ptr->Data->Layer[top_silk_layer].SelectedColor =
140     Settings.ElementSelectedColor;
141   ptr->Data->Layer[bottom_silk_layer].Color =
142     Settings.ShowBottomSide ?
143     Settings.ElementColor : Settings.InvisibleObjectsColor;
144   ptr->Data->Layer[bottom_silk_layer].SelectedColor =
145     Settings.ElementSelectedColor;
146 }
147 
148 /*!
149  * \brief Creates a new PCB.
150  */
151 PCBType *
CreateNewPCB(void)152 CreateNewPCB (void)
153 {
154   PCBType *ptr;
155   int i;
156 
157   /* allocate memory, switch all layers on and copy resources */
158   ptr = (PCBType *)calloc (1, sizeof (PCBType));
159   ptr->Data = CreateNewBuffer ();
160   ptr->Data->pcb = (PCBType *) ptr;
161   ptr->Data->polyClip = 1;
162 
163   ptr->ThermStyle = 4;
164   ptr->IsleArea = 2.e8;
165   ptr->SilkActive = false;
166   ptr->RatDraw = false;
167   SET_FLAG (NAMEONPCBFLAG, ptr);
168   if (Settings.ShowNumber)
169     SET_FLAG (SHOWNUMBERFLAG, ptr);
170   if (Settings.AllDirectionLines)
171     SET_FLAG (ALLDIRECTIONFLAG, ptr);
172   ptr->Clipping = 1;		/* this is the most useful starting point for now */
173   if (Settings.RubberBandMode)
174     SET_FLAG (RUBBERBANDFLAG, ptr);
175   if (Settings.SwapStartDirection)
176     SET_FLAG (SWAPSTARTDIRFLAG, ptr);
177   if (Settings.UniqueNames)
178     SET_FLAG (UNIQUENAMEFLAG, ptr);
179   if (Settings.SnapPin)
180     SET_FLAG (SNAPPINFLAG, ptr);
181   if (Settings.ClearLine)
182     SET_FLAG (CLEARNEWFLAG, ptr);
183   if (Settings.FullPoly)
184     SET_FLAG (NEWFULLPOLYFLAG, ptr);
185   if (Settings.OrthogonalMoves)
186     SET_FLAG (ORTHOMOVEFLAG, ptr);
187   if (Settings.liveRouting)
188     SET_FLAG (LIVEROUTEFLAG, ptr);
189   if (Settings.ShowDRC)
190     SET_FLAG (SHOWDRCFLAG, ptr);
191   if (Settings.AutoDRC)
192     SET_FLAG (AUTODRCFLAG, ptr);
193   if (Settings.AutoBuriedVias)
194     SET_FLAG (AUTOBURIEDVIASFLAG, ptr);
195   ptr->Grid = Settings.Grid;
196   ptr->LayerGroups = Settings.LayerGroups;
197   STYLE_LOOP (ptr);
198   {
199     *style = Settings.RouteStyle[n];
200     style->index = n;
201   }
202   END_LOOP;
203   ptr->MaxWidth = Settings.MaxWidth;
204   ptr->MaxHeight = Settings.MaxHeight;
205   ptr->ID = ID++;
206   ptr->ThermScale = 0.5;
207 
208   ptr->Bloat = Settings.Bloat;
209   ptr->Shrink = Settings.Shrink;
210   ptr->minWid = Settings.minWid;
211   ptr->minSlk = Settings.minSlk;
212   ptr->minDrill = Settings.minDrill;
213   ptr->minRing = Settings.minRing;
214 
215   for (i = 0; i < MAX_LAYER; i++)
216     ptr->Data->Layer[i].Name = strdup (Settings.DefaultLayerName[i]);
217 
218 	CreateDefaultFont (ptr);
219 
220   return (ptr);
221 }
222 
223 /*!
224  * \brief This post-processing step adds the top and bottom silk layers
225  * to a pre-existing PCB.
226  *
227  * Called after PCB->Data->LayerN is set.
228  *
229  * \return Returns zero if no errors, else nonzero.
230  */
231 int
CreateNewPCBPost(PCBType * pcb,int use_defaults)232 CreateNewPCBPost (PCBType *pcb, int use_defaults)
233 {
234   /* copy default settings */
235   pcb_colors_from_settings (pcb);
236 
237   if (use_defaults)
238     {
239       if (ParseGroupString (Settings.Groups, &pcb->LayerGroups, &pcb->Data->LayerN))
240 	return 1;
241     }
242 
243   pcb->Data->Layer[top_silk_layer].Name = strdup ("top silk");
244   pcb->Data->Layer[top_silk_layer].Type = LT_SILK;
245   pcb->Data->Layer[bottom_silk_layer].Name = strdup ("bottom silk");
246   pcb->Data->Layer[bottom_silk_layer].Type = LT_SILK;
247 
248   return 0;
249 }
250 
251 /*!
252  * \brief Creates a new via.
253  */
254 PinType *
CreateNewVia(DataType * Data,Coord X,Coord Y,Coord Thickness,Coord Clearance,Coord Mask,Coord DrillingHole,char * Name,FlagType Flags)255 CreateNewVia (DataType *Data,
256 	      Coord X, Coord Y,
257 	      Coord Thickness, Coord Clearance, Coord Mask,
258 	      Coord DrillingHole, char *Name, FlagType Flags)
259 {
260   PinType *Via;
261 
262   if (!be_lenient)
263     {
264       VIA_LOOP (Data);
265       {
266 	if (Distance (X, Y, via->X, via->Y) <=
267 	    via->DrillingHole / 2 + DrillingHole / 2)
268 	  {
269 	    Message (_("%m+Dropping via at %$mD because it's hole would overlap with the via "
270 		       "at %$mD\n"), Settings.grid_unit->allow, X, Y, via->X, via->Y);
271 	    return (NULL);		/* don't allow via stacking */
272 	  }
273       }
274       END_LOOP;
275     }
276 
277   Via = GetViaMemory (Data);
278 
279   if (!Via)
280     return (Via);
281   /* copy values */
282   Via->X = X;
283   Via->Y = Y;
284   Via->Thickness = Thickness;
285   Via->Clearance = Clearance;
286   Via->Mask = Mask;
287   Via->DrillingHole = vendorDrillMap (DrillingHole);
288   if (Via->DrillingHole != DrillingHole)
289     {
290       Message (_("%m+Mapped via drill hole to %$mS from %$mS per vendor table\n"),
291 	       Settings.grid_unit->allow, Via->DrillingHole, DrillingHole);
292     }
293 
294   Via->Name = STRDUP (Name);
295   Via->Flags = Flags;
296   Via->BuriedFrom = 0;
297   Via->BuriedTo = 0;
298   CLEAR_FLAG (WARNFLAG, Via);
299   SET_FLAG (VIAFLAG, Via);
300   Via->ID = ID++;
301 
302   /* Increase copper diameter to drill hole size if it's lower (unless
303      it's a mounting hole).  This will at least make incrementing the
304      via's copper size reasonably intuitive (i.e. it won't take
305      several increments before the copper is visible). */
306   if (!TEST_FLAG (HOLEFLAG, Via) &&
307       (Via->Thickness < Via->DrillingHole))
308     {
309       Via->Thickness = Via->DrillingHole;
310       Message (_("%m+Warning: Via's pad diameter was below hole size, "
311 		 "so pad diameter was increased to hole size at %$mD.\n"),
312 	       Settings.grid_unit->allow, Via->X, Via->Y);
313     }
314 
315   SetPinBoundingBox (Via);
316   if (!Data->via_tree)
317     Data->via_tree = r_create_tree (NULL, 0, 0);
318   r_insert_entry (Data->via_tree, (BoxType *) Via, 0);
319   return (Via);
320 }
321 
322 /*!
323  *  * \brief Creates a new via with buried info.
324  *   */
325 PinType *
CreateNewViaEx(DataType * Data,Coord X,Coord Y,Coord Thickness,Coord Clearance,Coord Mask,Coord DrillingHole,char * Name,FlagType Flags,Cardinal buried_from,Cardinal buried_to)326 CreateNewViaEx (DataType *Data,
327               Coord X, Coord Y,
328               Coord Thickness, Coord Clearance, Coord Mask,
329               Coord DrillingHole, char *Name, FlagType Flags,
330 	      Cardinal buried_from, Cardinal buried_to)
331 {
332   PinType *Via;
333 
334   Via = CreateNewVia (Data, X, Y, Thickness, Clearance, Mask,
335               DrillingHole, Name, Flags);
336   if (Via)
337     {
338       if (buried_from == buried_to)
339         {
340           Via->BuriedFrom = 0;
341           Via->BuriedTo = 0;
342 	}
343       else if (buried_from <= buried_to)
344         {
345           Via->BuriedFrom = buried_from;
346           Via->BuriedTo = buried_to;
347 	}
348       else
349         {
350           Via->BuriedFrom = buried_to;
351           Via->BuriedTo = buried_from;
352 	}
353     }
354   return Via;
355 }
356 
357 
358 struct line_info
359 {
360   Coord X1, X2, Y1, Y2;
361   Coord Thickness;
362   Coord Clearance;
363   FlagType Flags;
364   LineType test, *ans;
365   jmp_buf env;
366 };
367 
368 static int
line_callback(const BoxType * b,void * cl)369 line_callback (const BoxType * b, void *cl)
370 {
371   LineType *line = (LineType *) b;
372   struct line_info *i = (struct line_info *) cl;
373 
374   if (line->Point1.X == i->X1 &&
375       line->Point2.X == i->X2 &&
376       line->Point1.Y == i->Y1 && line->Point2.Y == i->Y2)
377     {
378       i->ans = (LineType *) (-1);
379       longjmp (i->env, 1);
380     }
381   /* check the other point order */
382   if (line->Point1.X == i->X1 &&
383       line->Point2.X == i->X2 &&
384       line->Point1.Y == i->Y1 && line->Point2.Y == i->Y2)
385     {
386       i->ans = (LineType *) (-1);
387       longjmp (i->env, 1);
388     }
389   if (line->Point2.X == i->X1 &&
390       line->Point1.X == i->X2 &&
391       line->Point2.Y == i->Y1 && line->Point1.Y == i->Y2)
392     {
393       i->ans = (LineType *) - 1;
394       longjmp (i->env, 1);
395     }
396   /* remove unnecessary line points */
397   if (line->Thickness == i->Thickness &&
398       /* don't merge lines if the clearances differ  */
399       line->Clearance == i->Clearance &&
400       /* don't merge lines if the clear flags differ  */
401       TEST_FLAG (CLEARLINEFLAG, line) == TEST_FLAG (CLEARLINEFLAG, i))
402     {
403       if (line->Point1.X == i->X1 && line->Point1.Y == i->Y1)
404 	{
405 	  i->test.Point1.X = line->Point2.X;
406 	  i->test.Point1.Y = line->Point2.Y;
407 	  i->test.Point2.X = i->X2;
408 	  i->test.Point2.Y = i->Y2;
409 	  if (IsPointOnLine (i->X1, i->Y1, 0.0, &i->test))
410 	    {
411 	      i->ans = line;
412 	      longjmp (i->env, 1);
413 	    }
414 	}
415       else if (line->Point2.X == i->X1 && line->Point2.Y == i->Y1)
416 	{
417 	  i->test.Point1.X = line->Point1.X;
418 	  i->test.Point1.Y = line->Point1.Y;
419 	  i->test.Point2.X = i->X2;
420 	  i->test.Point2.Y = i->Y2;
421 	  if (IsPointOnLine (i->X1, i->Y1, 0.0, &i->test))
422 	    {
423 	      i->ans = line;
424 	      longjmp (i->env, 1);
425 	    }
426 	}
427       else if (line->Point1.X == i->X2 && line->Point1.Y == i->Y2)
428 	{
429 	  i->test.Point1.X = line->Point2.X;
430 	  i->test.Point1.Y = line->Point2.Y;
431 	  i->test.Point2.X = i->X1;
432 	  i->test.Point2.Y = i->Y1;
433 	  if (IsPointOnLine (i->X2, i->Y2, 0.0, &i->test))
434 	    {
435 	      i->ans = line;
436 	      longjmp (i->env, 1);
437 	    }
438 	}
439       else if (line->Point2.X == i->X2 && line->Point2.Y == i->Y2)
440 	{
441 	  i->test.Point1.X = line->Point1.X;
442 	  i->test.Point1.Y = line->Point1.Y;
443 	  i->test.Point2.X = i->X1;
444 	  i->test.Point2.Y = i->Y1;
445 	  if (IsPointOnLine (i->X2, i->Y2, 0.0, &i->test))
446 	    {
447 	      i->ans = line;
448 	      longjmp (i->env, 1);
449 	    }
450 	}
451     }
452   return 0;
453 }
454 
455 
456 /*!
457  * \brief Creates a new line on a layer and checks for overlap and
458  * extension.
459  */
460 LineType *
CreateDrawnLineOnLayer(LayerType * Layer,Coord X1,Coord Y1,Coord X2,Coord Y2,Coord Thickness,Coord Clearance,FlagType Flags)461 CreateDrawnLineOnLayer (LayerType *Layer,
462 			Coord X1, Coord Y1,
463 			Coord X2, Coord Y2,
464 			Coord Thickness, Coord Clearance,
465 			FlagType Flags)
466 {
467   struct line_info info;
468   BoxType search;
469 
470   search.X1 = MIN (X1, X2);
471   search.X2 = MAX (X1, X2);
472   search.Y1 = MIN (Y1, Y2);
473   search.Y2 = MAX (Y1, Y2);
474   if (search.Y2 == search.Y1)
475     search.Y2++;
476   if (search.X2 == search.X1)
477     search.X2++;
478   info.X1 = X1;
479   info.X2 = X2;
480   info.Y1 = Y1;
481   info.Y2 = Y2;
482   info.Thickness = Thickness;
483   info.Clearance = Clearance;
484   info.Flags = Flags;
485   info.test.Thickness = 0;
486   info.test.Flags = NoFlags ();
487   info.ans = NULL;
488   /* prevent stacking of duplicate lines
489    * and remove needless intermediate points
490    * verify that the layer is on the board first!
491    */
492   if (setjmp (info.env) == 0)
493     {
494       r_search (Layer->line_tree, &search, NULL, line_callback, &info);
495       return CreateNewLineOnLayer (Layer, X1, Y1, X2, Y2,
496 				   Thickness, Clearance, Flags);
497     }
498 
499   if ((void *) info.ans == (void *) (-1))
500     return NULL;		/* stacked line */
501   /* remove unnecessary points */
502   if (info.ans)
503     {
504       /* must do this BEFORE getting new line memory */
505       MoveObjectToRemoveUndoList (LINE_TYPE, Layer, info.ans, info.ans);
506       X1 = info.test.Point1.X;
507       X2 = info.test.Point2.X;
508       Y1 = info.test.Point1.Y;
509       Y2 = info.test.Point2.Y;
510     }
511   return CreateNewLineOnLayer (Layer, X1, Y1, X2, Y2,
512 			       Thickness, Clearance, Flags);
513 }
514 
515 LineType *
CreateNewLineOnLayer(LayerType * Layer,Coord X1,Coord Y1,Coord X2,Coord Y2,Coord Thickness,Coord Clearance,FlagType Flags)516 CreateNewLineOnLayer (LayerType *Layer,
517 		      Coord X1, Coord Y1,
518 		      Coord X2, Coord Y2,
519 		      Coord Thickness, Coord Clearance,
520 		      FlagType Flags)
521 {
522   LineType *Line;
523 
524   Line = GetLineMemory (Layer);
525   if (!Line)
526     return (Line);
527   Line->ID = ID++;
528   Line->Flags = Flags;
529   CLEAR_FLAG (RATFLAG, Line);
530   Line->Thickness = Thickness;
531   Line->Clearance = Clearance;
532   Line->Point1.X = X1;
533   Line->Point1.Y = Y1;
534   Line->Point1.ID = ID++;
535   Line->Point2.X = X2;
536   Line->Point2.Y = Y2;
537   Line->Point2.ID = ID++;
538   SetLineBoundingBox (Line);
539   if (!Layer->line_tree)
540     Layer->line_tree = r_create_tree (NULL, 0, 0);
541   r_insert_entry (Layer->line_tree, (BoxType *) Line, 0);
542   return (Line);
543 }
544 
545 /*!
546  * \brief Creates a new rat-line.
547  */
548 RatType *
CreateNewRat(DataType * Data,Coord X1,Coord Y1,Coord X2,Coord Y2,Cardinal group1,Cardinal group2,Coord Thickness,FlagType Flags)549 CreateNewRat (DataType *Data, Coord X1, Coord Y1,
550 	      Coord X2, Coord Y2, Cardinal group1,
551 	      Cardinal group2, Coord Thickness, FlagType Flags)
552 {
553   RatType *Line = GetRatMemory (Data);
554 
555   if (!Line)
556     return (Line);
557 
558   Line->ID = ID++;
559   Line->Flags = Flags;
560   SET_FLAG (RATFLAG, Line);
561   Line->Thickness = Thickness;
562   Line->Point1.X = X1;
563   Line->Point1.Y = Y1;
564   Line->Point1.ID = ID++;
565   Line->Point2.X = X2;
566   Line->Point2.Y = Y2;
567   Line->Point2.ID = ID++;
568   Line->group1 = group1;
569   Line->group2 = group2;
570   SetLineBoundingBox ((LineType *) Line);
571   if (!Data->rat_tree)
572     Data->rat_tree = r_create_tree (NULL, 0, 0);
573   r_insert_entry (Data->rat_tree, &Line->BoundingBox, 0);
574   return (Line);
575 }
576 
577 /*!
578  * \brief Creates a new arc on a layer.
579  */
580 ArcType *
CreateNewArcOnLayer(LayerType * Layer,Coord X1,Coord Y1,Coord width,Coord height,Angle sa,Angle dir,Coord Thickness,Coord Clearance,FlagType Flags)581 CreateNewArcOnLayer (LayerType *Layer,
582 		     Coord X1, Coord Y1,
583 		     Coord width,
584 		     Coord height,
585 		     Angle sa,
586 		     Angle dir, Coord Thickness,
587 		     Coord Clearance, FlagType Flags)
588 {
589   ArcType *Arc;
590 
591   ARC_LOOP (Layer);
592   {
593     if (arc->X == X1 && arc->Y == Y1 && arc->Width == width &&
594 	NormalizeAngle (arc->StartAngle) == NormalizeAngle (sa) &&
595 	arc->Delta == dir)
596       return (NULL);		/* prevent stacked arcs */
597   }
598   END_LOOP;
599   Arc = GetArcMemory (Layer);
600   if (!Arc)
601     return (Arc);
602 
603   Arc->ID = ID++;
604   Arc->Flags = Flags;
605   Arc->Thickness = Thickness;
606   Arc->Clearance = Clearance;
607   Arc->X = X1;
608   Arc->Y = Y1;
609   Arc->Width = width;
610   Arc->Height = height;
611   Arc->StartAngle = sa;
612   Arc->Delta = dir;
613   SetArcBoundingBox (Arc);
614   if (!Layer->arc_tree)
615     Layer->arc_tree = r_create_tree (NULL, 0, 0);
616   r_insert_entry (Layer->arc_tree, (BoxType *) Arc, 0);
617   return (Arc);
618 }
619 
620 
621 /*!
622  * \brief Creates a new polygon from the old formats rectangle data.
623  */
624 PolygonType *
CreateNewPolygonFromRectangle(LayerType * Layer,Coord X1,Coord Y1,Coord X2,Coord Y2,FlagType Flags)625 CreateNewPolygonFromRectangle (LayerType *Layer,
626 			       Coord X1, Coord Y1,
627 			       Coord X2, Coord Y2,
628 			       FlagType Flags)
629 {
630   PolygonType *polygon = CreateNewPolygon (Layer, Flags);
631   if (!polygon)
632     return (polygon);
633 
634   CreateNewPointInPolygon (polygon, X1, Y1);
635   CreateNewPointInPolygon (polygon, X2, Y1);
636   CreateNewPointInPolygon (polygon, X2, Y2);
637   CreateNewPointInPolygon (polygon, X1, Y2);
638   SetPolygonBoundingBox (polygon);
639   if (!Layer->polygon_tree)
640     Layer->polygon_tree = r_create_tree (NULL, 0, 0);
641   r_insert_entry (Layer->polygon_tree, (BoxType *) polygon, 0);
642   return (polygon);
643 }
644 
645 /*!
646  * \brief Creates a new text on a layer.
647  */
648 TextType *
CreateNewText(LayerType * Layer,FontType * PCBFont,Coord X,Coord Y,unsigned Direction,int Scale,char * TextString,FlagType Flags)649 CreateNewText (LayerType *Layer, FontType *PCBFont,
650 	       Coord X, Coord Y,
651 	       unsigned Direction, int Scale, char *TextString, FlagType Flags)
652 {
653   TextType *text;
654 
655   if (TextString == NULL)
656     return NULL;
657 
658   text = GetTextMemory (Layer);
659   if (text == NULL)
660     return NULL;
661 
662   /* copy values, width and height are set by drawing routine
663    * because at this point we don't know which symbols are available
664    */
665   text->X = X;
666   text->Y = Y;
667   text->Direction = Direction;
668   text->Flags = Flags;
669   text->Scale = Scale;
670   text->TextString = strdup (TextString);
671 
672   /* calculate size of the bounding box */
673   SetTextBoundingBox (PCBFont, text);
674   text->ID = ID++;
675   if (!Layer->text_tree)
676     Layer->text_tree = r_create_tree (NULL, 0, 0);
677   r_insert_entry (Layer->text_tree, (BoxType *) text, 0);
678   return (text);
679 }
680 
681 /*!
682  * \brief Creates a new polygon on a layer.
683  */
684 PolygonType *
CreateNewPolygon(LayerType * Layer,FlagType Flags)685 CreateNewPolygon (LayerType *Layer, FlagType Flags)
686 {
687   PolygonType *polygon = GetPolygonMemory (Layer);
688 
689   /* copy values */
690   polygon->Flags = Flags;
691   polygon->ID = ID++;
692   polygon->Clipped = NULL;
693   polygon->NoHoles = NULL;
694   polygon->NoHolesValid = 0;
695   return (polygon);
696 }
697 
698 /*!
699  * \brief Creates a new point in a polygon.
700  */
701 PointType *
CreateNewPointInPolygon(PolygonType * Polygon,Coord X,Coord Y)702 CreateNewPointInPolygon (PolygonType *Polygon, Coord X, Coord Y)
703 {
704   PointType *point = GetPointMemoryInPolygon (Polygon);
705 
706   /* copy values */
707   point->X = X;
708   point->Y = Y;
709   point->ID = ID++;
710   return (point);
711 }
712 
713 /*!
714  * \brief Creates a new hole in a polygon.
715  */
716 PolygonType *
CreateNewHoleInPolygon(PolygonType * Polygon)717 CreateNewHoleInPolygon (PolygonType *Polygon)
718 {
719   Cardinal *holeindex = GetHoleIndexMemoryInPolygon (Polygon);
720   *holeindex = Polygon->PointN;
721   return Polygon;
722 }
723 
724 /*!
725  * \brief Creates an new element.
726  *
727  * \note Memory is allocated if needed.
728  */
729 ElementType *
CreateNewElement(DataType * Data,FontType * PCBFont,FlagType Flags,char * Description,char * NameOnPCB,char * Value,Coord TextX,Coord TextY,BYTE Direction,int TextScale,FlagType TextFlags,bool uniqueName)730 CreateNewElement (DataType *Data, FontType *PCBFont, FlagType Flags,
731 		  char *Description, char *NameOnPCB, char *Value,
732 		  Coord TextX, Coord TextY, BYTE Direction,
733 		  int TextScale, FlagType TextFlags, bool uniqueName)
734 {
735   ElementType *Element;
736 
737 #ifdef DEBUG_CREATE_C
738   printf("Entered CreateNewElement.....\n");
739 #endif
740 
741   Element = GetElementMemory (Data);
742 
743   /* copy values and set additional information */
744   TextScale = MAX (MIN_TEXTSCALE, TextScale);
745   AddTextToElement (&DESCRIPTION_TEXT (Element), PCBFont, TextX, TextY,
746 		    Direction, Description, TextScale, TextFlags);
747   if (uniqueName)
748     NameOnPCB = UniqueElementName (Data, NameOnPCB);
749   AddTextToElement (&NAMEONPCB_TEXT (Element), PCBFont, TextX, TextY,
750 		    Direction, NameOnPCB, TextScale, TextFlags);
751   AddTextToElement (&VALUE_TEXT (Element), PCBFont, TextX, TextY,
752 		    Direction, Value, TextScale, TextFlags);
753   DESCRIPTION_TEXT (Element).Element = Element;
754   NAMEONPCB_TEXT (Element).Element = Element;
755   VALUE_TEXT (Element).Element = Element;
756   Element->Flags = Flags;
757   Element->ID = ID++;
758 
759 #ifdef DEBUG_CREATE_C
760   printf("  .... Leaving CreateNewElement.\n");
761 #endif
762 
763   return (Element);
764 }
765 
766 /*!
767  * \brief Creates a new arc in an element.
768  */
769 ArcType *
CreateNewArcInElement(ElementType * Element,Coord X,Coord Y,Coord Width,Coord Height,Angle angle,Angle delta,Coord Thickness)770 CreateNewArcInElement (ElementType *Element,
771 		       Coord X, Coord Y,
772 		       Coord Width, Coord Height,
773 		       Angle angle, Angle delta, Coord Thickness)
774 {
775   ArcType *arc;
776 
777   arc = g_slice_new0 (ArcType);
778   Element->Arc = g_list_append (Element->Arc, arc);
779   Element->ArcN ++;
780 
781   /* set Delta (0,360], StartAngle in [0,360) */
782   if (delta < 0)
783     {
784       delta = -delta;
785       angle -= delta;
786     }
787   angle = NormalizeAngle (angle);
788   delta = NormalizeAngle (delta);
789   if (delta == 0)
790     delta = 360;
791 
792   /* copy values */
793   arc->X = X;
794   arc->Y = Y;
795   arc->Width = Width;
796   arc->Height = Height;
797   arc->StartAngle = angle;
798   arc->Delta = delta;
799   arc->Thickness = Thickness;
800   arc->ID = ID++;
801   return arc;
802 }
803 
804 /*!
805  * \brief Creates a new line for an element.
806  */
807 LineType *
CreateNewLineInElement(ElementType * Element,Coord X1,Coord Y1,Coord X2,Coord Y2,Coord Thickness)808 CreateNewLineInElement (ElementType *Element,
809 			Coord X1, Coord Y1,
810 			Coord X2, Coord Y2,
811 			Coord Thickness)
812 {
813   LineType *line;
814 
815   if (Thickness == 0)
816     return NULL;
817 
818   line = g_slice_new0 (LineType);
819   Element->Line = g_list_append (Element->Line, line);
820   Element->LineN ++;
821 
822   /* copy values */
823   line->Point1.X = X1;
824   line->Point1.Y = Y1;
825   line->Point2.X = X2;
826   line->Point2.Y = Y2;
827   line->Thickness = Thickness;
828   line->Flags = NoFlags ();
829   line->ID = ID++;
830   return line;
831 }
832 
833 /*!
834  * \brief Creates a new pin in an element.
835  */
836 PinType *
CreateNewPin(ElementType * Element,Coord X,Coord Y,Coord Thickness,Coord Clearance,Coord Mask,Coord DrillingHole,char * Name,char * Number,FlagType Flags)837 CreateNewPin (ElementType *Element,
838 	      Coord X, Coord Y,
839 	      Coord Thickness, Coord Clearance, Coord Mask,
840 	      Coord DrillingHole, char *Name, char *Number,
841 	      FlagType Flags)
842 {
843   PinType *pin = GetPinMemory (Element);
844 
845   /* copy values */
846   pin->X = X;
847   pin->Y = Y;
848   pin->Thickness = Thickness;
849   pin->Clearance = Clearance;
850   pin->Mask = Mask;
851   pin->Name = STRDUP (Name);
852   pin->Number = STRDUP (Number);
853   pin->Flags = Flags;
854   CLEAR_FLAG (WARNFLAG, pin);
855   SET_FLAG (PINFLAG, pin);
856   pin->ID = ID++;
857   pin->Element = Element;
858 
859   /*
860    * If there is no vendor drill map installed, this will simply
861    * return DrillingHole.
862    */
863   pin->DrillingHole = vendorDrillMap (DrillingHole);
864 
865   /* Unless we should not map drills on this element, map them! */
866   if (vendorIsElementMappable (Element))
867     {
868       if (pin->DrillingHole < MIN_PINORVIASIZE)
869 	{
870 	  Message (_("%m+Did not map pin #%s (%s) drill hole because %$mS is below the minimum allowed size\n"),
871 		   Settings.grid_unit->allow, UNKNOWN (Number), UNKNOWN (Name), pin->DrillingHole);
872 	  pin->DrillingHole = DrillingHole;
873 	}
874       else if (pin->DrillingHole > MAX_PINORVIASIZE)
875 	{
876 	  Message (_("%m+Did not map pin #%s (%s) drill hole because %$mS is above the maximum allowed size\n"),
877 		   Settings.grid_unit->allow, UNKNOWN (Number), UNKNOWN (Name), pin->DrillingHole);
878 	  pin->DrillingHole = DrillingHole;
879 	}
880       else if (!TEST_FLAG (HOLEFLAG, pin)
881 	       && (pin->DrillingHole > pin->Thickness))
882 	{
883 	  Message (_("%m+Did not map pin #%s (%s) drill hole because %$mS does not leave any copper\n"),
884 		   Settings.grid_unit->allow, UNKNOWN (Number), UNKNOWN (Name), pin->DrillingHole);
885 	  pin->DrillingHole = DrillingHole;
886 	}
887     }
888   else
889     {
890       pin->DrillingHole = DrillingHole;
891     }
892 
893   if (pin->DrillingHole != DrillingHole)
894     {
895       Message (_("%m+Mapped pin drill hole to %$mS from %$mS per vendor table\n"),
896 	       Settings.grid_unit->allow, pin->DrillingHole, DrillingHole);
897     }
898 
899   return (pin);
900 }
901 
902 /*!
903  * \brief Creates a new pad in an element.
904  */
905 PadType *
CreateNewPad(ElementType * Element,Coord X1,Coord Y1,Coord X2,Coord Y2,Coord Thickness,Coord Clearance,Coord Mask,char * Name,char * Number,FlagType Flags)906 CreateNewPad (ElementType *Element,
907 	      Coord X1, Coord Y1, Coord X2,
908 	      Coord Y2, Coord Thickness, Coord Clearance,
909 	      Coord Mask, char *Name, char *Number, FlagType Flags)
910 {
911   PadType *pad = GetPadMemory (Element);
912 
913   /* copy values */
914   if (X1 > X2 || (X1 == X2 && Y1 > Y2))
915     {
916       pad->Point1.X = X2;
917       pad->Point1.Y = Y2;
918       pad->Point2.X = X1;
919       pad->Point2.Y = Y1;
920     }
921   else
922     {
923       pad->Point1.X = X1;
924       pad->Point1.Y = Y1;
925       pad->Point2.X = X2;
926       pad->Point2.Y = Y2;
927     }
928   pad->Thickness = Thickness;
929   pad->Clearance = Clearance;
930   pad->Mask = Mask;
931   pad->Name = STRDUP (Name);
932   pad->Number = STRDUP (Number);
933   pad->Flags = Flags;
934   CLEAR_FLAG (WARNFLAG, pad);
935   pad->ID = ID++;
936   pad->Element = Element;
937   return (pad);
938 }
939 
940 /*!
941  * \brief Creates a new textobject as part of an element.
942  *
943  * Copies the values to the appropriate text object.
944  */
945 static void
AddTextToElement(TextType * Text,FontType * PCBFont,Coord X,Coord Y,unsigned Direction,char * TextString,int Scale,FlagType Flags)946 AddTextToElement (TextType *Text, FontType *PCBFont,
947 		  Coord X, Coord Y,
948 		  unsigned Direction, char *TextString, int Scale, FlagType Flags)
949 {
950   free (Text->TextString);
951   Text->TextString = (TextString && *TextString) ? strdup (TextString) : NULL;
952   Text->X = X;
953   Text->Y = Y;
954   Text->Direction = Direction;
955   Text->Flags = Flags;
956   Text->Scale = Scale;
957 
958   /* calculate size of the bounding box */
959   SetTextBoundingBox (PCBFont, Text);
960   Text->ID = ID++;
961 }
962 
963 /*!
964  * \brief Creates a new line in a symbol.
965  */
966 LineType *
CreateNewLineInSymbol(SymbolType * Symbol,Coord X1,Coord Y1,Coord X2,Coord Y2,Coord Thickness)967 CreateNewLineInSymbol (SymbolType *Symbol,
968 		       Coord X1, Coord Y1,
969 		       Coord X2, Coord Y2, Coord Thickness)
970 {
971   LineType *line = Symbol->Line;
972 
973   /* realloc new memory if necessary and clear it */
974   if (Symbol->LineN >= Symbol->LineMax)
975     {
976       Symbol->LineMax += STEP_SYMBOLLINE;
977       line = (LineType *)realloc (line, Symbol->LineMax * sizeof (LineType));
978       Symbol->Line = line;
979       memset (line + Symbol->LineN, 0, STEP_SYMBOLLINE * sizeof (LineType));
980     }
981 
982   /* copy values */
983   line = line + Symbol->LineN++;
984   line->Point1.X = X1;
985   line->Point1.Y = Y1;
986   line->Point2.X = X2;
987   line->Point2.Y = Y2;
988   line->Thickness = Thickness;
989   return (line);
990 }
991 
992 /*!
993  * \brief Parses a file with font information and installs it into the
994  * provided PCB.
995  *
996  * Checks directories given as colon separated list by resource fontPath
997  * if the fonts filename doesn't contain a directory component.
998  */
999 void
CreateDefaultFont(PCBType * pcb)1000 CreateDefaultFont (PCBType *pcb)
1001 {
1002   if (ParseFont (&pcb->Font, Settings.FontFile))
1003     Message (_("Can't find font-symbol-file '%s'\n"), Settings.FontFile);
1004 }
1005 
1006 /*!
1007  * \brief Adds a new line to the rubberband list of
1008  * 'Crosshair.AttachedObject'.
1009  *
1010  * If Layer == 0  it is a rat line.
1011  */
1012 RubberbandType *
CreateNewRubberbandEntry(LayerType * Layer,LineType * Line,PointType * MovedPoint)1013 CreateNewRubberbandEntry (LayerType *Layer,
1014 			  LineType *Line, PointType *MovedPoint)
1015 {
1016   RubberbandType *ptr = GetRubberbandMemory ();
1017 
1018   /* we toggle the RUBBERENDFLAG of the line to determine if */
1019   /* both points are being moved. */
1020   TOGGLE_FLAG (RUBBERENDFLAG, Line);
1021   ptr->Layer = Layer;
1022   ptr->Line = Line;
1023   ptr->MovedPoint = MovedPoint;
1024   return (ptr);
1025 }
1026 
1027 /*!
1028  * \brief Add a new net to the netlist menu.
1029  */
1030 LibraryMenuType *
CreateNewNet(LibraryType * lib,char * name,char * style)1031 CreateNewNet (LibraryType *lib, char *name, char *style)
1032 {
1033   LibraryMenuType *menu;
1034   char temp[64];
1035 
1036   sprintf (temp, "  %s", name);
1037   menu = GetLibraryMenuMemory (lib);
1038   menu->Name = strdup (temp);
1039   menu->flag = 1;		/* net is enabled by default */
1040   if (style == NULL || NSTRCMP ("(unknown)", style) == 0)
1041     menu->Style = NULL;
1042   else
1043     menu->Style = strdup (style);
1044   return (menu);
1045 }
1046 
1047 /*!
1048  * \brief Add a connection to the net.
1049  */
1050 LibraryEntryType *
CreateNewConnection(LibraryMenuType * net,char * conn)1051 CreateNewConnection (LibraryMenuType *net, char *conn)
1052 {
1053   LibraryEntryType *entry = GetLibraryEntryMemory (net);
1054 
1055   entry->ListEntry = STRDUP (conn);
1056   return (entry);
1057 }
1058 
1059 /*!
1060  * \brief Add an attribute to a list..
1061  */
1062 AttributeType *
CreateNewAttribute(AttributeListType * list,char * name,char * value)1063 CreateNewAttribute (AttributeListType *list, char *name, char *value)
1064 {
1065   if (list->Number >= list->Max)
1066     {
1067       list->Max += 10;
1068       list->List = (AttributeType *)realloc (list->List, list->Max * sizeof (AttributeType));
1069     }
1070   list->List[list->Number].name = STRDUP (name);
1071   list->List[list->Number].value = STRDUP (value);
1072   list->Number++;
1073   return &list->List[list->Number - 1];
1074 }
1075 
1076 /*
1077  * Actions
1078  */
1079 
1080 static const char create_via_syntax[] =
1081 N_("CreateVia(x,y,[unit])\n");
1082 
1083 static const char create_via_help[] =
1084 N_("Add a via to the board.");
1085 
1086 static int
create_via_action(int argc,char ** argv,Coord x,Coord y)1087 create_via_action(int argc, char **argv, Coord x, Coord y)
1088 {
1089   char *x_str = ARG (0);
1090   char *y_str = ARG (1);
1091   char *units = ARG (2);
1092   Coord nx, ny;
1093   bool absolute1, absolute2;
1094   PinType *via;
1095 
1096   ny = GetValue (y_str, units, &absolute1);
1097   nx = GetValue (x_str, units, &absolute2);
1098 
1099   if (!absolute1 || !absolute2) {
1100     Message(
1101             "CreateVia action does not currently support relative placements.\n");
1102   }
1103 
1104   via = CreateNewVia(PCB->Data, nx, ny, Settings.ViaThickness,
1105                      2*Settings.Keepaway, Settings.ViaMaskAperture,
1106                      Settings.ViaDrillingHole, NULL, NoFlags());
1107 
1108   return via->ID;
1109 }
1110 
1111 static HID_Action create_action_list[] =
1112 {
1113   {"CreateVia", NULL, create_via_action,
1114     create_via_help, create_via_syntax}
1115 };
1116 
1117 REGISTER_ACTIONS (create_action_list)
1118