polygon1.c: Tidy up label_contour() following node_label() changes
[geda-pcb/gde.git] / src / report.c
blob974c0bef439fdd4182e292387ad56d283f742b19
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 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 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1),
335 TEST_FLAG (LOCKFLAG, Polygon) ? "It is LOCKED\n" : "");
336 break;
338 case PAD_TYPE:
340 int len, dx, dy, mgap;
341 PadTypePtr Pad;
342 ElementTypePtr element;
343 #ifndef NDEBUG
344 if (gui->shift_is_pressed ())
346 __r_dump_tree (PCB->Data->pad_tree->root, 0);
347 return 0;
349 #endif
350 Pad = (PadTypePtr) ptr2;
351 element = (ElementTypePtr) ptr1;
353 PAD_LOOP (element);
356 if (pad == Pad)
357 break;
360 END_LOOP;
361 dx = Pad->Point1.X - Pad->Point2.X;
362 dy = Pad->Point1.Y - Pad->Point2.Y;
363 len = sqrt (dx*dx+dy*dy);
364 mgap = (Pad->Mask - Pad->Thickness)/2;
365 sprintf (&report[0], "PAD ID# %ld Flags:%s\n"
366 "FirstPoint(X,Y) = (%d, %d) ID = %ld\n"
367 "SecondPoint(X,Y) = (%d, %d) ID = %ld\n"
368 "Width = %0.2f %s. Length = %0.2f %s.\n"
369 "Clearance width in polygons = %0.2f %s.\n"
370 "Solder mask = %0.2f x %0.2f %s (gap = %0.2f %s).\n"
371 "Name = \"%s\"\n"
372 "It is owned by SMD element %s\n"
373 "As pin number %s and is on the %s\n"
374 "side of the board.\n"
375 "%s", Pad->ID,
376 flags_to_string (Pad->Flags, PAD_TYPE),
377 Pad->Point1.X, Pad->Point1.Y, Pad->Point1.ID,
378 Pad->Point2.X, Pad->Point2.Y, Pad->Point2.ID,
379 UNIT (Pad->Thickness), UNIT (len + Pad->Thickness),
380 UNIT (Pad->Clearance / 2.),
381 UNIT1 (Pad->Mask), UNIT (Pad->Mask + len), UNIT (mgap),
382 EMPTY (Pad->Name),
383 EMPTY (element->Name[1].TextString),
384 EMPTY (Pad->Number),
385 TEST_FLAG (ONSOLDERFLAG,
386 Pad) ? "solder (bottom)" : "component",
387 TEST_FLAG (LOCKFLAG, Pad) ? "It is LOCKED\n" : "");
388 break;
390 case ELEMENT_TYPE:
392 ElementTypePtr element;
393 #ifndef NDEBUG
394 if (gui->shift_is_pressed ())
396 __r_dump_tree (PCB->Data->element_tree->root, 0);
397 return 0;
399 #endif
400 element = (ElementTypePtr) ptr2;
401 sprintf (&report[0], "ELEMENT ID# %ld Flags:%s\n"
402 "BoundingBox (%d,%d) (%d,%d)\n"
403 "Descriptive Name \"%s\"\n"
404 "Name on board \"%s\"\n"
405 "Part number name \"%s\"\n"
406 "It is %0.2f %s tall and is located at (X,Y) = (%d,%d)\n"
407 "%s"
408 "Mark located at point (X,Y) = (%d,%d)\n"
409 "It is on the %s side of the board.\n"
410 "%s",
411 element->ID, flags_to_string (element->Flags, ELEMENT_TYPE),
412 element->BoundingBox.X1, element->BoundingBox.Y1,
413 element->BoundingBox.X2, element->BoundingBox.Y2,
414 EMPTY (element->Name[0].TextString),
415 EMPTY (element->Name[1].TextString),
416 EMPTY (element->Name[2].TextString),
417 UNIT (0.45 * element->Name[1].Scale * 100.), element->Name[1].X,
418 element->Name[1].Y, TEST_FLAG (HIDENAMEFLAG, element) ?
419 "But it's hidden\n" : "", element->MarkX,
420 element->MarkY, TEST_FLAG (ONSOLDERFLAG,
421 element) ? "solder (bottom)" :
422 "component", TEST_FLAG (LOCKFLAG, element) ?
423 "It is LOCKED\n" : "");
424 break;
426 case TEXT_TYPE:
427 #ifndef NDEBUG
428 if (gui->shift_is_pressed ())
430 LayerTypePtr layer = (LayerTypePtr) ptr1;
431 __r_dump_tree (layer->text_tree->root, 0);
432 return 0;
434 #endif
435 case ELEMENTNAME_TYPE:
437 char laynum[32];
438 TextTypePtr text;
439 #ifndef NDEBUG
440 if (gui->shift_is_pressed ())
442 __r_dump_tree (PCB->Data->name_tree[NAME_INDEX (PCB)]->root, 0);
443 return 0;
445 #endif
446 text = (TextTypePtr) ptr2;
448 if (type == TEXT_TYPE)
449 sprintf (laynum, "is on layer %d",
450 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1));
451 sprintf (&report[0], "TEXT ID# %ld Flags:%s\n"
452 "Located at (X,Y) = (%d,%d)\n"
453 "Characters are %0.2f %s tall\n"
454 "Value is \"%s\"\n"
455 "Direction is %d\n"
456 "The bounding box is (%d,%d) (%d, %d)\n"
457 "It %s\n"
458 "%s", text->ID, flags_to_string (text->Flags, TEXT_TYPE),
459 text->X, text->Y, UNIT (0.45 * text->Scale * 100.),
460 text->TextString, text->Direction,
461 text->BoundingBox.X1, text->BoundingBox.Y1,
462 text->BoundingBox.X2, text->BoundingBox.Y2,
463 (type == TEXT_TYPE) ? laynum : "is an element name.",
464 TEST_FLAG (LOCKFLAG, text) ? "It is LOCKED\n" : "");
465 break;
467 case LINEPOINT_TYPE:
468 case POLYGONPOINT_TYPE:
470 PointTypePtr point = (PointTypePtr) ptr2;
471 sprintf (&report[0], "POINT ID# %ld. Points don't have flags.\n"
472 "Located at (X,Y) = (%d,%d)\n"
473 "It belongs to a %s on layer %d\n", point->ID,
474 point->X, point->Y,
475 (type == LINEPOINT_TYPE) ? "line" : "polygon",
476 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1));
477 break;
479 case NO_TYPE:
480 report[0] = '\0';
481 break;
483 default:
484 sprintf (&report[0], "Unknown\n");
485 break;
488 if (report[0] == '\0')
490 Message (_("Nothing found to report on\n"));
491 return 1;
493 HideCrosshair (False);
494 /* create dialog box */
495 gui->report_dialog ("Report", &report[0]);
497 RestoreCrosshair (False);
498 return 0;
501 static int
502 ReportFoundPins (int argc, char **argv, int x, int y)
504 static DynamicStringType list;
505 char temp[64];
506 int col = 0;
508 DSClearString (&list);
509 DSAddString (&list, "The following pins/pads are FOUND:\n");
510 ELEMENT_LOOP (PCB->Data);
512 PIN_LOOP (element);
514 if (TEST_FLAG (FOUNDFLAG, pin))
516 sprintf (temp, "%s-%s,%c",
517 NAMEONPCB_NAME (element),
518 pin->Number,
519 ((col++ % (COLUMNS + 1)) == COLUMNS) ? '\n' : ' ');
520 DSAddString (&list, temp);
523 END_LOOP;
524 PAD_LOOP (element);
526 if (TEST_FLAG (FOUNDFLAG, pad))
528 sprintf (temp, "%s-%s,%c",
529 NAMEONPCB_NAME (element), pad->Number,
530 ((col++ % (COLUMNS + 1)) == COLUMNS) ? '\n' : ' ');
531 DSAddString (&list, temp);
534 END_LOOP;
536 END_LOOP;
538 HideCrosshair (False);
539 gui->report_dialog ("Report", list.Data);
540 RestoreCrosshair (False);
541 return 0;
544 static double
545 XYtoNetLength (int x, int y, int *found)
547 double length;
549 length = 0;
550 *found = 0;
551 LookupConnection (x, y, True, PCB->Grid, FOUNDFLAG);
553 ALLLINE_LOOP (PCB->Data);
555 if (TEST_FLAG (FOUNDFLAG, line))
557 double l;
558 int dx, dy;
559 dx = line->Point1.X - line->Point2.X;
560 dy = line->Point1.Y - line->Point2.Y;
561 l = sqrt ((double)dx*dx + (double)dy*dy);
562 length += l;
563 *found = 1;
566 ENDALL_LOOP;
568 ALLARC_LOOP (PCB->Data);
570 if (TEST_FLAG (FOUNDFLAG, arc))
572 double l;
573 /* FIXME: we assume width==height here */
574 l = M_PI * 2*arc->Width * abs(arc->Delta)/360.0;
575 length += l;
576 *found = 1;
579 ENDALL_LOOP;
581 return length;
584 static int
585 ReportAllNetLengths (int argc, char **argv, int x, int y)
587 enum { Upcb, Umm, Umil, Uin } units;
588 int ni;
589 int found;
590 double length;
592 units = Settings.grid_units_mm ? Umm : Umil;
594 if (argc >= 1)
596 printf("Units: %s\n", argv[0]);
597 if (strcasecmp (argv[0], "mm") == 0)
598 units = Umm;
599 else if (strcasecmp (argv[0], "mil") == 0)
600 units = Umil;
601 else if (strcasecmp (argv[0], "in") == 0)
602 units = Uin;
603 else
604 units = Upcb;
607 for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++)
609 char *netname = PCB->NetlistLib.Menu[ni].Name + 2;
610 char *ename = PCB->NetlistLib.Menu[ni].Entry[0].ListEntry;
611 char *pname;
613 ename = strdup (ename);
614 pname = strchr (ename, '-');
615 if (! pname)
617 free (ename);
618 continue;
620 *pname++ = 0;
622 ELEMENT_LOOP (PCB->Data);
624 char *es = element->Name[NAMEONPCB_INDEX].TextString;
625 if (es && strcmp (es, ename) == 0)
627 PIN_LOOP (element);
629 if (strcmp (pin->Number, pname) == 0)
631 x = pin->X;
632 y = pin->Y;
633 goto got_one;
636 END_LOOP;
637 PAD_LOOP (element);
639 if (strcmp (pad->Number, pname) == 0)
641 x = (pad->Point1.X + pad->Point2.X) / 2;
642 y = (pad->Point1.Y + pad->Point2.Y) / 2;
643 goto got_one;
646 END_LOOP;
649 END_LOOP;
651 continue;
653 got_one:
654 SaveUndoSerialNumber ();
655 ResetFoundPinsViasAndPads (True);
656 RestoreUndoSerialNumber ();
657 ResetFoundLinesAndPolygons (True);
658 RestoreUndoSerialNumber ();
659 length = XYtoNetLength (x, y, &found);
661 switch (units)
663 case Upcb:
664 gui->log("Net %s length %d\n", netname, (int)length);
665 break;
666 case Umm:
667 length *= COOR_TO_MM;
668 gui->log("Net %s length %.2f mm\n", netname, length);
669 break;
670 case Umil:
671 length /= 100;
672 gui->log("Net %s length %d mil\n", netname, (int)length);
673 break;
674 case Uin:
675 length /= 100000.0;
676 gui->log("Net %s length %.3f in\n", netname, length);
677 break;
682 static int
683 ReportNetLength (int argc, char **argv, int x, int y)
685 double length = 0;
686 char *netname = 0;
687 int found = 0;
689 SaveUndoSerialNumber ();
690 ResetFoundPinsViasAndPads (True);
691 RestoreUndoSerialNumber ();
692 ResetFoundLinesAndPolygons (True);
693 RestoreUndoSerialNumber ();
694 gui->get_coords ("Click on a connection", &x, &y);
696 XYtoNetLength (x, y, &found);
698 if (!found)
700 gui->log ("No net under cursor.\n");
701 return 1;
704 ELEMENT_LOOP (PCB->Data);
706 PIN_LOOP (element);
708 if (TEST_FLAG (FOUNDFLAG, pin))
710 int ni, nei;
711 char *ename = element->Name[NAMEONPCB_INDEX].TextString;
712 char *pname = pin->Number;
713 char *n;
715 if (ename && pname)
717 n = Concat (ename, "-", pname, NULL);
718 for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++)
719 for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++)
721 if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0)
723 netname = PCB->NetlistLib.Menu[ni].Name + 2;
724 goto got_net_name; /* four for loops deep */
730 END_LOOP;
731 PAD_LOOP (element);
733 if (TEST_FLAG (FOUNDFLAG, pad))
735 int ni, nei;
736 char *ename = element->Name[NAMEONPCB_INDEX].TextString;
737 char *pname = pad->Number;
738 char *n;
740 if (ename && pname)
742 n = Concat (ename, "-", pname, NULL);
743 for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++)
744 for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++)
746 if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0)
748 netname = PCB->NetlistLib.Menu[ni].Name + 2;
749 goto got_net_name; /* four for loops deep */
755 END_LOOP;
757 END_LOOP;
758 got_net_name:
760 HideCrosshair (False);
761 if (netname)
762 gui->log ("Net %s length: %0.2f %s\n", netname, UNIT (length));
763 else
764 gui->log ("Net length: %0.2f %s\n", UNIT (length));
765 RestoreCrosshair (False);
766 return 0;
768 /* ---------------------------------------------------------------------------
769 * reports on an object
770 * syntax:
773 static const char report_syntax[] = "Report(Object|DrillReport|FoundPins|NetLength|AllNetLengths)";
775 static const char report_help[] = "Produce various report.";
777 /* %start-doc actions Report
779 @table @code
781 @item Object
782 The object under the crosshair will be reported, describing various
783 aspects of the object.
785 @item DrillReport
786 A report summarizing the number of drill sizes used, and how many of
787 each, will be produced.
789 @item FoundPins
790 A report listing all pins and pads which are marked as ``found'' will
791 be produced.
793 @item NetLength
794 The name and length of the net under the crosshair will be reported to
795 the message log.
797 @item AllNetLengths
798 The name and length of the net under the crosshair will be reported to
799 the message log. An optional parameter specifies mm, mil, pcb, or in
800 units
802 @end table
804 %end-doc */
806 static int
807 Report (int argc, char **argv, int x, int y)
809 if (argc < 1)
810 AUSAGE (report);
811 else if (strcasecmp (argv[0], "Object") == 0)
813 gui->get_coords ("Click on an object", &x, &y);
814 return ReportDialog (argc - 1, argv + 1, x, y);
816 else if (strcasecmp (argv[0], "DrillReport") == 0)
817 return ReportDrills (argc - 1, argv + 1, x, y);
818 else if (strcasecmp (argv[0], "FoundPins") == 0)
819 return ReportFoundPins (argc - 1, argv + 1, x, y);
820 else if (strcasecmp (argv[0], "NetLength") == 0)
821 return ReportNetLength (argc - 1, argv + 1, x, y);
822 else if (strcasecmp (argv[0], "AllNetLengths") == 0)
823 return ReportAllNetLengths (argc - 1, argv + 1, x, y);
824 else
825 AFAIL (report);
826 return 1;
829 HID_Action report_action_list[] = {
830 {"ReportObject", "Click on an object", ReportDialog,
831 reportdialog_help, reportdialog_syntax}
833 {"Report", 0, Report,
834 report_help, report_syntax}
837 REGISTER_ACTIONS (report_action_list)