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