Introduce POLYGONHOLE_MODE for creating holes in polygons
[geda-pcb/gde.git] / src / report.c
blobdc01153080b764061a3dacedddb61326562d9427
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996,1997,1998,1999 Thomas Nau
9 * This module, report.c, was written and is Copyright (C) 1997 harry eaton
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 * Contact addresses for paper mail and Email:
26 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
27 * Thomas.Nau@rz.uni-ulm.de
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
36 #include <math.h>
38 #include "report.h"
39 #include "crosshair.h"
40 #include "data.h"
41 #include "drill.h"
42 #include "error.h"
43 #include "search.h"
44 #include "misc.h"
45 #include "mymem.h"
46 #include "rtree.h"
47 #include "strflags.h"
48 #include "macro.h"
49 #include "undo.h"
50 #include "find.h"
52 #ifdef HAVE_LIBDMALLOC
53 #include <dmalloc.h>
54 #endif
56 RCSID ("$Id$");
59 #define UNIT1(value) (Settings.grid_units_mm ? ((value) / 100000.0 * 25.4) : ((value) / 100.0))
60 #define UNIT(value) UNIT1(value) , (Settings.grid_units_mm ? "mm" : "mils")
62 static int
63 ReportDrills (int argc, char **argv, int x, int y)
65 DrillInfoTypePtr AllDrills;
66 Cardinal n;
67 char *stringlist, *thestring;
68 int total_drills = 0;
70 AllDrills = GetDrillInfo (PCB->Data);
71 RoundDrillInfo (AllDrills, 100);
73 for (n = 0; n < AllDrills->DrillN; n++)
75 total_drills += AllDrills->Drill[n].PinCount;
76 total_drills += AllDrills->Drill[n].ViaCount;
77 total_drills += AllDrills->Drill[n].UnplatedCount;
80 stringlist = malloc (512L + AllDrills->DrillN * 64L);
82 /* Use tabs for formatting since can't count on a fixed font anymore.
83 | And even that probably isn't going to work in all cases.
85 sprintf (stringlist,
86 "There are %d different drill sizes used in this layout, %d holes total\n\n"
87 "Drill Diam. (mils)\t# of Pins\t# of Vias\t# of Elements\t# Unplated\n",
88 AllDrills->DrillN, total_drills);
89 thestring = stringlist;
90 while (*thestring != '\0')
91 thestring++;
92 for (n = 0; n < AllDrills->DrillN; n++)
94 sprintf (thestring,
95 "\t%d\t\t\t%d\t\t%d\t\t%d\t\t%d\n",
96 (AllDrills->Drill[n].DrillSize+50) / 100,
97 AllDrills->Drill[n].PinCount, AllDrills->Drill[n].ViaCount,
98 AllDrills->Drill[n].ElementN,
99 AllDrills->Drill[n].UnplatedCount);
100 while (*thestring != '\0')
101 thestring++;
103 FreeDrillInfo (AllDrills);
104 /* create dialog box */
105 gui->report_dialog ("Drill Report", stringlist);
107 SaveFree (stringlist);
108 return 0;
112 static const char reportdialog_syntax[] = "ReportDialog()";
114 static const char reportdialog_help[] =
115 "Report on the object under the crosshair";
117 /* %start-doc actions ReportDialog
119 This is a shortcut for @code{Report(Object)}.
121 %end-doc */
123 static int
124 ReportDialog (int argc, char **argv, int x, int y)
126 void *ptr1, *ptr2, *ptr3;
127 int type;
128 char report[2048];
130 type = SearchScreen (x, y, REPORT_TYPES, &ptr1, &ptr2, &ptr3);
131 if (type == NO_TYPE)
132 type =
133 SearchScreen (x, y, REPORT_TYPES | LOCKED_TYPE, &ptr1, &ptr2, &ptr3);
135 switch (type)
137 case VIA_TYPE:
139 PinTypePtr via;
140 #ifndef NDEBUG
141 if (gui->shift_is_pressed ())
143 __r_dump_tree (PCB->Data->via_tree->root, 0);
144 return 0;
146 #endif
147 via = (PinTypePtr) ptr2;
148 if (TEST_FLAG (HOLEFLAG, via))
149 sprintf (&report[0], "VIA ID# %ld Flags:%s\n"
150 "(X,Y) = (%d, %d)\n"
151 "It is a pure hole of diameter %0.2f %s\n"
152 "Name = \"%s\""
153 "%s", via->ID, flags_to_string (via->Flags, VIA_TYPE),
154 via->X, via->Y, UNIT (via->DrillingHole),
155 EMPTY (via->Name), TEST_FLAG (LOCKFLAG,
156 via) ? "It is LOCKED\n" :
157 "");
158 else
159 sprintf (&report[0], "VIA ID# %ld Flags:%s\n"
160 "(X,Y) = (%d, %d)\n"
161 "Copper width = %0.2f %s Drill width = %0.2f %s\n"
162 "Clearance width in polygons = %0.2f %s\n"
163 "Annulus = %0.2f %s\n"
164 "Solder mask hole = %0.2f %s (gap = %0.2f %s)\n"
165 "Name = \"%s\""
166 "%s", via->ID, flags_to_string (via->Flags, VIA_TYPE),
167 via->X, via->Y, UNIT (via->Thickness),
168 UNIT (via->DrillingHole), UNIT (via->Clearance / 2.),
169 UNIT ((via->Thickness - via->DrillingHole)/2),
170 UNIT (via->Mask), UNIT ((via->Mask - via->Thickness)/2),
171 EMPTY (via->Name), TEST_FLAG (LOCKFLAG, via) ?
172 "It is LOCKED\n" : "");
173 break;
175 case PIN_TYPE:
177 PinTypePtr Pin;
178 ElementTypePtr element;
179 #ifndef NDEBUG
180 if (gui->shift_is_pressed ())
182 __r_dump_tree (PCB->Data->pin_tree->root, 0);
183 return 0;
185 #endif
186 Pin = (PinTypePtr) ptr2;
187 element = (ElementTypePtr) ptr1;
189 PIN_LOOP (element);
191 if (pin == Pin)
192 break;
194 END_LOOP;
195 if (TEST_FLAG (HOLEFLAG, Pin))
196 sprintf (&report[0], "PIN ID# %ld Flags:%s\n"
197 "(X,Y) = (%d, %d)\n"
198 "It is a mounting hole, Drill width = %0.2f %s\n"
199 "It is owned by element %s\n"
200 "%s", Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE),
201 Pin->X, Pin->Y, UNIT (Pin->DrillingHole),
202 EMPTY (element->Name[1].TextString),
203 TEST_FLAG (LOCKFLAG, Pin) ? "It is LOCKED\n" : "");
204 else
205 sprintf (&report[0],
206 "PIN ID# %ld Flags:%s\n" "(X,Y) = (%d, %d)\n"
207 "Copper width = %0.2f %s Drill width = %0.2f %s\n"
208 "Clearance width to Polygon = %0.2f %s\n"
209 "Annulus = %0.2f %s\n"
210 "Solder mask hole = %0.2f %s (gap = %0.2f %s)\n"
211 "Name = \"%s\"\n"
212 "It is owned by element %s\n" "As pin number %s\n"
213 "%s",
214 Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE),
215 Pin->X, Pin->Y, UNIT (Pin->Thickness),
216 UNIT (Pin->DrillingHole), UNIT (Pin->Clearance / 2.),
217 UNIT ((Pin->Thickness - Pin->DrillingHole)/2),
218 UNIT (Pin->Mask), UNIT ((Pin->Mask - Pin->Thickness)/2),
219 EMPTY (Pin->Name),
220 EMPTY (element->Name[1].TextString), EMPTY (Pin->Number),
221 TEST_FLAG (LOCKFLAG, Pin) ? "It is LOCKED\n" : "");
222 break;
224 case LINE_TYPE:
226 LineTypePtr line;
227 #ifndef NDEBUG
228 if (gui->shift_is_pressed ())
230 LayerTypePtr layer = (LayerTypePtr) ptr1;
231 __r_dump_tree (layer->line_tree->root, 0);
232 return 0;
234 #endif
235 line = (LineTypePtr) ptr2;
236 sprintf (&report[0], "LINE ID# %ld Flags:%s\n"
237 "FirstPoint(X,Y) = (%d, %d) ID = %ld\n"
238 "SecondPoint(X,Y) = (%d, %d) ID = %ld\n"
239 "Width = %0.2f %s.\nClearance width in polygons = %0.2f %s.\n"
240 "It is on layer %d\n"
241 "and has name %s\n"
242 "%s",
243 line->ID, flags_to_string (line->Flags, LINE_TYPE),
244 line->Point1.X, line->Point1.Y,
245 line->Point1.ID, line->Point2.X, line->Point2.Y,
246 line->Point2.ID, UNIT (line->Thickness),
247 UNIT (line->Clearance / 2.), GetLayerNumber (PCB->Data,
248 (LayerTypePtr) ptr1),
249 UNKNOWN (line->Number), TEST_FLAG (LOCKFLAG,
250 line) ? "It is LOCKED\n" :
251 "");
252 break;
254 case RATLINE_TYPE:
256 RatTypePtr line;
257 #ifndef NDEBUG
258 if (gui->shift_is_pressed ())
260 __r_dump_tree (PCB->Data->rat_tree->root, 0);
261 return 0;
263 #endif
264 line = (RatTypePtr) ptr2;
265 sprintf (&report[0], "RAT-LINE ID# %ld Flags:%s\n"
266 "FirstPoint(X,Y) = (%d, %d) ID = %ld "
267 "connects to layer group %d\n"
268 "SecondPoint(X,Y) = (%d, %d) ID = %ld "
269 "connects to layer group %d\n",
270 line->ID, flags_to_string (line->Flags, LINE_TYPE),
271 line->Point1.X, line->Point1.Y,
272 line->Point1.ID, line->group1,
273 line->Point2.X, line->Point2.Y,
274 line->Point2.ID, line->group2);
275 break;
277 case ARC_TYPE:
279 ArcTypePtr Arc;
280 BoxTypePtr box;
281 #ifndef NDEBUG
282 if (gui->shift_is_pressed ())
284 LayerTypePtr layer = (LayerTypePtr) ptr1;
285 __r_dump_tree (layer->arc_tree->root, 0);
286 return 0;
288 #endif
289 Arc = (ArcTypePtr) ptr2;
290 box = GetArcEnds (Arc);
292 sprintf (&report[0], "ARC ID# %ld Flags:%s\n"
293 "CenterPoint(X,Y) = (%d, %d)\n"
294 "Radius = %0.2f %s, Thickness = %0.2f %s\n"
295 "Clearance width in polygons = %0.2f %s\n"
296 "StartAngle = %ld degrees, DeltaAngle = %ld degrees\n"
297 "Bounding Box is (%d,%d), (%d,%d)\n"
298 "That makes the end points at (%d,%d) and (%d,%d)\n"
299 "It is on layer %d\n"
300 "%s", Arc->ID, flags_to_string (Arc->Flags, ARC_TYPE),
301 Arc->X, Arc->Y, UNIT (Arc->Width), UNIT (Arc->Thickness),
302 UNIT (Arc->Clearance / 2.), Arc->StartAngle, Arc->Delta,
303 Arc->BoundingBox.X1, Arc->BoundingBox.Y1,
304 Arc->BoundingBox.X2, Arc->BoundingBox.Y2, box->X1,
305 box->Y1, box->X2, box->Y2, GetLayerNumber (PCB->Data,
306 (LayerTypePtr)
307 ptr1),
308 TEST_FLAG (LOCKFLAG, Arc) ? "It is LOCKED\n" : "");
309 break;
311 case POLYGON_TYPE:
313 PolygonTypePtr Polygon;
314 #ifndef NDEBUG
315 if (gui->shift_is_pressed ())
317 LayerTypePtr layer = (LayerTypePtr) ptr1;
318 __r_dump_tree (layer->polygon_tree->root, 0);
319 return;
321 #endif
322 Polygon = (PolygonTypePtr) ptr2;
324 sprintf (&report[0], "POLYGON ID# %ld Flags:%s\n"
325 "Its bounding box is (%d,%d) (%d,%d)\n"
326 "It has %d points and could store %d more\n"
327 "without using more memory.\n"
328 "It has %d holes and resides on layer %d\n"
329 "%s", Polygon->ID,
330 flags_to_string (Polygon->Flags, POLYGON_TYPE),
331 Polygon->BoundingBox.X1, Polygon->BoundingBox.Y1,
332 Polygon->BoundingBox.X2, Polygon->BoundingBox.Y2,
333 Polygon->PointN, Polygon->PointMax - Polygon->PointN,
334 Polygon->HoleIndexN,
335 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1),
336 TEST_FLAG (LOCKFLAG, Polygon) ? "It is LOCKED\n" : "");
337 break;
339 case PAD_TYPE:
341 int len, dx, dy, mgap;
342 PadTypePtr Pad;
343 ElementTypePtr element;
344 #ifndef NDEBUG
345 if (gui->shift_is_pressed ())
347 __r_dump_tree (PCB->Data->pad_tree->root, 0);
348 return 0;
350 #endif
351 Pad = (PadTypePtr) ptr2;
352 element = (ElementTypePtr) ptr1;
354 PAD_LOOP (element);
357 if (pad == Pad)
358 break;
361 END_LOOP;
362 dx = Pad->Point1.X - Pad->Point2.X;
363 dy = Pad->Point1.Y - Pad->Point2.Y;
364 len = sqrt (dx*dx+dy*dy);
365 mgap = (Pad->Mask - Pad->Thickness)/2;
366 sprintf (&report[0], "PAD ID# %ld Flags:%s\n"
367 "FirstPoint(X,Y) = (%d, %d) ID = %ld\n"
368 "SecondPoint(X,Y) = (%d, %d) ID = %ld\n"
369 "Width = %0.2f %s. Length = %0.2f %s.\n"
370 "Clearance width in polygons = %0.2f %s.\n"
371 "Solder mask = %0.2f x %0.2f %s (gap = %0.2f %s).\n"
372 "Name = \"%s\"\n"
373 "It is owned by SMD element %s\n"
374 "As pin number %s and is on the %s\n"
375 "side of the board.\n"
376 "%s", Pad->ID,
377 flags_to_string (Pad->Flags, PAD_TYPE),
378 Pad->Point1.X, Pad->Point1.Y, Pad->Point1.ID,
379 Pad->Point2.X, Pad->Point2.Y, Pad->Point2.ID,
380 UNIT (Pad->Thickness), UNIT (len + Pad->Thickness),
381 UNIT (Pad->Clearance / 2.),
382 UNIT1 (Pad->Mask), UNIT (Pad->Mask + len), UNIT (mgap),
383 EMPTY (Pad->Name),
384 EMPTY (element->Name[1].TextString),
385 EMPTY (Pad->Number),
386 TEST_FLAG (ONSOLDERFLAG,
387 Pad) ? "solder (bottom)" : "component",
388 TEST_FLAG (LOCKFLAG, Pad) ? "It is LOCKED\n" : "");
389 break;
391 case ELEMENT_TYPE:
393 ElementTypePtr element;
394 #ifndef NDEBUG
395 if (gui->shift_is_pressed ())
397 __r_dump_tree (PCB->Data->element_tree->root, 0);
398 return 0;
400 #endif
401 element = (ElementTypePtr) ptr2;
402 sprintf (&report[0], "ELEMENT ID# %ld Flags:%s\n"
403 "BoundingBox (%d,%d) (%d,%d)\n"
404 "Descriptive Name \"%s\"\n"
405 "Name on board \"%s\"\n"
406 "Part number name \"%s\"\n"
407 "It is %0.2f %s tall and is located at (X,Y) = (%d,%d)\n"
408 "%s"
409 "Mark located at point (X,Y) = (%d,%d)\n"
410 "It is on the %s side of the board.\n"
411 "%s",
412 element->ID, flags_to_string (element->Flags, ELEMENT_TYPE),
413 element->BoundingBox.X1, element->BoundingBox.Y1,
414 element->BoundingBox.X2, element->BoundingBox.Y2,
415 EMPTY (element->Name[0].TextString),
416 EMPTY (element->Name[1].TextString),
417 EMPTY (element->Name[2].TextString),
418 UNIT (0.45 * element->Name[1].Scale * 100.), element->Name[1].X,
419 element->Name[1].Y, TEST_FLAG (HIDENAMEFLAG, element) ?
420 "But it's hidden\n" : "", element->MarkX,
421 element->MarkY, TEST_FLAG (ONSOLDERFLAG,
422 element) ? "solder (bottom)" :
423 "component", TEST_FLAG (LOCKFLAG, element) ?
424 "It is LOCKED\n" : "");
425 break;
427 case TEXT_TYPE:
428 #ifndef NDEBUG
429 if (gui->shift_is_pressed ())
431 LayerTypePtr layer = (LayerTypePtr) ptr1;
432 __r_dump_tree (layer->text_tree->root, 0);
433 return 0;
435 #endif
436 case ELEMENTNAME_TYPE:
438 char laynum[32];
439 TextTypePtr text;
440 #ifndef NDEBUG
441 if (gui->shift_is_pressed ())
443 __r_dump_tree (PCB->Data->name_tree[NAME_INDEX (PCB)]->root, 0);
444 return 0;
446 #endif
447 text = (TextTypePtr) ptr2;
449 if (type == TEXT_TYPE)
450 sprintf (laynum, "is on layer %d",
451 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1));
452 sprintf (&report[0], "TEXT ID# %ld Flags:%s\n"
453 "Located at (X,Y) = (%d,%d)\n"
454 "Characters are %0.2f %s tall\n"
455 "Value is \"%s\"\n"
456 "Direction is %d\n"
457 "The bounding box is (%d,%d) (%d, %d)\n"
458 "It %s\n"
459 "%s", text->ID, flags_to_string (text->Flags, TEXT_TYPE),
460 text->X, text->Y, UNIT (0.45 * text->Scale * 100.),
461 text->TextString, text->Direction,
462 text->BoundingBox.X1, text->BoundingBox.Y1,
463 text->BoundingBox.X2, text->BoundingBox.Y2,
464 (type == TEXT_TYPE) ? laynum : "is an element name.",
465 TEST_FLAG (LOCKFLAG, text) ? "It is LOCKED\n" : "");
466 break;
468 case LINEPOINT_TYPE:
469 case POLYGONPOINT_TYPE:
471 PointTypePtr point = (PointTypePtr) ptr2;
472 sprintf (&report[0], "POINT ID# %ld. Points don't have flags.\n"
473 "Located at (X,Y) = (%d,%d)\n"
474 "It belongs to a %s on layer %d\n", point->ID,
475 point->X, point->Y,
476 (type == LINEPOINT_TYPE) ? "line" : "polygon",
477 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1));
478 break;
480 case NO_TYPE:
481 report[0] = '\0';
482 break;
484 default:
485 sprintf (&report[0], "Unknown\n");
486 break;
489 if (report[0] == '\0')
491 Message (_("Nothing found to report on\n"));
492 return 1;
494 HideCrosshair (false);
495 /* create dialog box */
496 gui->report_dialog ("Report", &report[0]);
498 RestoreCrosshair (false);
499 return 0;
502 static int
503 ReportFoundPins (int argc, char **argv, int x, int y)
505 static DynamicStringType list;
506 char temp[64];
507 int col = 0;
509 DSClearString (&list);
510 DSAddString (&list, "The following pins/pads are FOUND:\n");
511 ELEMENT_LOOP (PCB->Data);
513 PIN_LOOP (element);
515 if (TEST_FLAG (FOUNDFLAG, pin))
517 sprintf (temp, "%s-%s,%c",
518 NAMEONPCB_NAME (element),
519 pin->Number,
520 ((col++ % (COLUMNS + 1)) == COLUMNS) ? '\n' : ' ');
521 DSAddString (&list, temp);
524 END_LOOP;
525 PAD_LOOP (element);
527 if (TEST_FLAG (FOUNDFLAG, pad))
529 sprintf (temp, "%s-%s,%c",
530 NAMEONPCB_NAME (element), pad->Number,
531 ((col++ % (COLUMNS + 1)) == COLUMNS) ? '\n' : ' ');
532 DSAddString (&list, temp);
535 END_LOOP;
537 END_LOOP;
539 HideCrosshair (false);
540 gui->report_dialog ("Report", list.Data);
541 RestoreCrosshair (false);
542 return 0;
545 static double
546 XYtoNetLength (int x, int y, int *found)
548 double length;
550 length = 0;
551 *found = 0;
552 LookupConnection (x, y, true, PCB->Grid, FOUNDFLAG);
554 ALLLINE_LOOP (PCB->Data);
556 if (TEST_FLAG (FOUNDFLAG, line))
558 double l;
559 int dx, dy;
560 dx = line->Point1.X - line->Point2.X;
561 dy = line->Point1.Y - line->Point2.Y;
562 l = sqrt ((double)dx*dx + (double)dy*dy);
563 length += l;
564 *found = 1;
567 ENDALL_LOOP;
569 ALLARC_LOOP (PCB->Data);
571 if (TEST_FLAG (FOUNDFLAG, arc))
573 double l;
574 /* FIXME: we assume width==height here */
575 l = M_PI * 2*arc->Width * abs(arc->Delta)/360.0;
576 length += l;
577 *found = 1;
580 ENDALL_LOOP;
582 return length;
585 static int
586 ReportAllNetLengths (int argc, char **argv, int x, int y)
588 enum { Upcb, Umm, Umil, Uin } units;
589 int ni;
590 int found;
591 double length;
593 units = Settings.grid_units_mm ? Umm : Umil;
595 if (argc >= 1)
597 printf("Units: %s\n", argv[0]);
598 if (strcasecmp (argv[0], "mm") == 0)
599 units = Umm;
600 else if (strcasecmp (argv[0], "mil") == 0)
601 units = Umil;
602 else if (strcasecmp (argv[0], "in") == 0)
603 units = Uin;
604 else
605 units = Upcb;
608 for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++)
610 char *netname = PCB->NetlistLib.Menu[ni].Name + 2;
611 char *ename = PCB->NetlistLib.Menu[ni].Entry[0].ListEntry;
612 char *pname;
614 ename = strdup (ename);
615 pname = strchr (ename, '-');
616 if (! pname)
618 free (ename);
619 continue;
621 *pname++ = 0;
623 ELEMENT_LOOP (PCB->Data);
625 char *es = element->Name[NAMEONPCB_INDEX].TextString;
626 if (es && strcmp (es, ename) == 0)
628 PIN_LOOP (element);
630 if (strcmp (pin->Number, pname) == 0)
632 x = pin->X;
633 y = pin->Y;
634 goto got_one;
637 END_LOOP;
638 PAD_LOOP (element);
640 if (strcmp (pad->Number, pname) == 0)
642 x = (pad->Point1.X + pad->Point2.X) / 2;
643 y = (pad->Point1.Y + pad->Point2.Y) / 2;
644 goto got_one;
647 END_LOOP;
650 END_LOOP;
652 continue;
654 got_one:
655 SaveUndoSerialNumber ();
656 ResetFoundPinsViasAndPads (true);
657 RestoreUndoSerialNumber ();
658 ResetFoundLinesAndPolygons (true);
659 RestoreUndoSerialNumber ();
660 length = XYtoNetLength (x, y, &found);
662 switch (units)
664 case Upcb:
665 gui->log("Net %s length %d\n", netname, (int)length);
666 break;
667 case Umm:
668 length *= COOR_TO_MM;
669 gui->log("Net %s length %.2f mm\n", netname, length);
670 break;
671 case Umil:
672 length /= 100;
673 gui->log("Net %s length %d mil\n", netname, (int)length);
674 break;
675 case Uin:
676 length /= 100000.0;
677 gui->log("Net %s length %.3f in\n", netname, length);
678 break;
681 return 0;
684 static int
685 ReportNetLength (int argc, char **argv, int x, int y)
687 double length = 0;
688 char *netname = 0;
689 int found = 0;
691 SaveUndoSerialNumber ();
692 ResetFoundPinsViasAndPads (true);
693 RestoreUndoSerialNumber ();
694 ResetFoundLinesAndPolygons (true);
695 RestoreUndoSerialNumber ();
696 gui->get_coords ("Click on a connection", &x, &y);
698 length = XYtoNetLength (x, y, &found);
700 if (!found)
702 gui->log ("No net under cursor.\n");
703 return 1;
706 ELEMENT_LOOP (PCB->Data);
708 PIN_LOOP (element);
710 if (TEST_FLAG (FOUNDFLAG, pin))
712 int ni, nei;
713 char *ename = element->Name[NAMEONPCB_INDEX].TextString;
714 char *pname = pin->Number;
715 char *n;
717 if (ename && pname)
719 n = Concat (ename, "-", pname, NULL);
720 for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++)
721 for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++)
723 if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0)
725 netname = PCB->NetlistLib.Menu[ni].Name + 2;
726 goto got_net_name; /* four for loops deep */
732 END_LOOP;
733 PAD_LOOP (element);
735 if (TEST_FLAG (FOUNDFLAG, pad))
737 int ni, nei;
738 char *ename = element->Name[NAMEONPCB_INDEX].TextString;
739 char *pname = pad->Number;
740 char *n;
742 if (ename && pname)
744 n = Concat (ename, "-", pname, NULL);
745 for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++)
746 for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++)
748 if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0)
750 netname = PCB->NetlistLib.Menu[ni].Name + 2;
751 goto got_net_name; /* four for loops deep */
757 END_LOOP;
759 END_LOOP;
760 got_net_name:
762 HideCrosshair (false);
763 if (netname)
764 gui->log ("Net %s length: %0.2f %s\n", netname, UNIT (length));
765 else
766 gui->log ("Net length: %0.2f %s\n", UNIT (length));
767 RestoreCrosshair (false);
768 return 0;
770 /* ---------------------------------------------------------------------------
771 * reports on an object
772 * syntax:
775 static const char report_syntax[] = "Report(Object|DrillReport|FoundPins|NetLength|AllNetLengths)";
777 static const char report_help[] = "Produce various report.";
779 /* %start-doc actions Report
781 @table @code
783 @item Object
784 The object under the crosshair will be reported, describing various
785 aspects of the object.
787 @item DrillReport
788 A report summarizing the number of drill sizes used, and how many of
789 each, will be produced.
791 @item FoundPins
792 A report listing all pins and pads which are marked as ``found'' will
793 be produced.
795 @item NetLength
796 The name and length of the net under the crosshair will be reported to
797 the message log.
799 @item AllNetLengths
800 The name and length of the net under the crosshair will be reported to
801 the message log. An optional parameter specifies mm, mil, pcb, or in
802 units
804 @end table
806 %end-doc */
808 static int
809 Report (int argc, char **argv, int x, int y)
811 if (argc < 1)
812 AUSAGE (report);
813 else if (strcasecmp (argv[0], "Object") == 0)
815 gui->get_coords ("Click on an object", &x, &y);
816 return ReportDialog (argc - 1, argv + 1, x, y);
818 else if (strcasecmp (argv[0], "DrillReport") == 0)
819 return ReportDrills (argc - 1, argv + 1, x, y);
820 else if (strcasecmp (argv[0], "FoundPins") == 0)
821 return ReportFoundPins (argc - 1, argv + 1, x, y);
822 else if (strcasecmp (argv[0], "NetLength") == 0)
823 return ReportNetLength (argc - 1, argv + 1, x, y);
824 else if (strcasecmp (argv[0], "AllNetLengths") == 0)
825 return ReportAllNetLengths (argc - 1, argv + 1, x, y);
826 else
827 AFAIL (report);
828 return 1;
831 HID_Action report_action_list[] = {
832 {"ReportObject", "Click on an object", ReportDialog,
833 reportdialog_help, reportdialog_syntax}
835 {"Report", 0, Report,
836 report_help, report_syntax}
839 REGISTER_ACTIONS (report_action_list)