autocrop.c

00001 /* autocrop plug-in for PCB
00002 
00003    Reduce the board dimensions to just enclose the elements.
00004 
00005    Copyright (C) 2007 Ben Jackson <ben@ben.com> based on teardrops.c by
00006    Copyright (C) 2006 DJ Delorie <dj@delorie.com>
00007 
00008    Licensed under the terms of the GNU General Public License, version
00009    2 or later.
00010 */
00011 
00012 #include <stdio.h>
00013 #include <math.h>
00014 
00015 #include "global.h"
00016 #include "data.h"
00017 #include "hid.h"
00018 #include "misc.h"
00019 #include "create.h"
00020 #include "rtree.h"
00021 #include "undo.h"
00022 #include "move.h"
00023 #include "draw.h"
00024 #include "set.h"
00025 #include "polygon.h"
00026 
00027 static void *
00028 MyMoveViaLowLevel(DataTypePtr Data, PinTypePtr Via, LocationType dx, LocationType dy)
00029 {
00030         if (Data) {
00031                 RestoreToPolygon(Data, VIA_TYPE, Via, Via);
00032                 r_delete_entry(Data->via_tree, (BoxTypePtr) Via);
00033         }
00034         MOVE_VIA_LOWLEVEL(Via, dx, dy);
00035         if (Data) {
00036                 r_insert_entry(Data->via_tree, (BoxTypePtr) Via, 0);
00037                 ClearFromPolygon(Data, VIA_TYPE, Via, Via);
00038         }
00039         return Via;
00040 }
00041 
00042 static void *
00043 MyMoveLineLowLevel(DataTypePtr Data, LayerTypePtr Layer, LineTypePtr Line, LocationType dx, LocationType dy)
00044 {
00045         if (Data) {
00046                 RestoreToPolygon(Data, LINE_TYPE, Layer, Line);
00047                 r_delete_entry(Layer->line_tree, (BoxTypePtr) Line);
00048         }
00049         MOVE_LINE_LOWLEVEL(Line, dx, dy);
00050         if (Data) {
00051                 r_insert_entry(Layer->line_tree, (BoxTypePtr) Line, 0);
00052                 ClearFromPolygon(Data, LINE_TYPE, Layer, Line);
00053         }
00054         return Line;
00055 }
00056 
00057 static void *
00058 MyMoveArcLowLevel(DataTypePtr Data, LayerTypePtr Layer, ArcTypePtr Arc, LocationType dx, LocationType dy)
00059 {
00060         if (Data) {
00061                 RestoreToPolygon(Data, ARC_TYPE, Layer, Arc);
00062                 r_delete_entry(Layer->arc_tree, (BoxTypePtr) Arc);
00063         }
00064         MOVE_ARC_LOWLEVEL(Arc, dx, dy);
00065         if (Data) {
00066                 r_insert_entry(Layer->arc_tree, (BoxTypePtr) Arc, 0);
00067                 ClearFromPolygon(Data, ARC_TYPE, Layer, Arc);
00068         }
00069         return Arc;
00070 }
00071 
00072 static void *
00073 MyMovePolygonLowLevel(DataTypePtr Data, LayerTypePtr Layer, PolygonTypePtr Polygon, LocationType dx, LocationType dy)
00074 {
00075         if (Data) {
00076                 r_delete_entry(Layer->polygon_tree, (BoxTypePtr) Polygon);
00077         }
00078         /* move.c actually only moves points, note no Data/Layer args */
00079         MovePolygonLowLevel(Polygon, dx, dy);
00080         if (Data) {
00081                 r_insert_entry(Layer->polygon_tree, (BoxTypePtr) Polygon, 0);
00082                 InitClip(Data, Layer, Polygon);
00083         }
00084         return Polygon;
00085 }
00086 
00087 static void *
00088 MyMoveTextLowLevel(LayerTypePtr Layer, TextTypePtr Text, LocationType dx, LocationType dy)
00089 {
00090         if (Layer)
00091                 r_delete_entry(Layer->text_tree, (BoxTypePtr) Text);
00092         MOVE_TEXT_LOWLEVEL(Text, dx, dy);
00093         if (Layer)
00094                 r_insert_entry(Layer->text_tree, (BoxTypePtr) Text, 0);
00095         return Text;
00096 }
00097 
00098 /*
00099  * Move everything.  Call our own 'MyMove*LowLevel' where they don't exist
00100  * in move.c.  This gets very slow if there are large polygons present,
00101  * since every element move re-clears the poly, followed by the polys
00102  * moving and re-clearing everything again.
00103  */
00104 static void
00105 MoveAll(LocationType dx, LocationType dy)
00106 {
00107         ELEMENT_LOOP(PCB->Data);
00108         {
00109                 MoveElementLowLevel(PCB->Data, element, dx, dy);
00110                 AddObjectToMoveUndoList(ELEMENT_TYPE, NULL, NULL, element, dx, dy);
00111         }
00112         END_LOOP;
00113 
00114         VIA_LOOP(PCB->Data);
00115         {
00116                 MyMoveViaLowLevel(PCB->Data, via, dx, dy);
00117                 AddObjectToMoveUndoList(VIA_TYPE, NULL, NULL, via, dx, dy);
00118         }
00119         END_LOOP;
00120 
00121         ALLLINE_LOOP(PCB->Data);
00122         {
00123                 MyMoveLineLowLevel(PCB->Data, layer, line, dx, dy);
00124                 AddObjectToMoveUndoList(LINE_TYPE, NULL, NULL, line, dx, dy);
00125         }
00126         ENDALL_LOOP;
00127 
00128         ALLARC_LOOP(PCB->Data);
00129         {
00130                 MyMoveArcLowLevel(PCB->Data, layer, arc, dx, dy);
00131                 AddObjectToMoveUndoList(ARC_TYPE, NULL, NULL, arc, dx, dy);
00132         }
00133         ENDALL_LOOP;
00134 
00135         ALLTEXT_LOOP(PCB->Data);
00136         {
00137                 MyMoveTextLowLevel(layer, text, dx, dy);
00138                 AddObjectToMoveUndoList(TEXT_TYPE, NULL, NULL, text, dx, dy);
00139         }
00140         ENDALL_LOOP;
00141 
00142         ALLPOLYGON_LOOP(PCB->Data);
00143         {
00144                 /*
00145                  * XXX MovePolygonLowLevel does not mean "no gui" like
00146                  * XXX MoveElementLowLevel, it doesn't even handle layer
00147                  * XXX tree activity.
00148                  */
00149                 MyMovePolygonLowLevel(PCB->Data, layer, polygon, dx, dy);
00150                 AddObjectToMoveUndoList(POLYGON_TYPE, NULL, NULL, polygon, dx, dy);
00151         }
00152         ENDALL_LOOP;
00153 }
00154 
00155 static int
00156 autocrop(int argc, char **argv, int x, int y)
00157 {
00158 //      int changed = 0;
00159         LocationType dx, dy, pad;
00160         BoxTypePtr box;
00161 
00162         box = GetDataBoundingBox(PCB->Data);    /* handy! */
00163 
00164         if (!box || (box->X1 == box->X2 || box->Y1 == box->Y2)) {
00165                 /* board would become degenerate */
00166                 return 0;
00167         }
00168 
00169         /*
00170          * Now X1/Y1 are the distance to move the left/top edge
00171          * (actually moving all components to the left/up) such that
00172          * the exact edge of the leftmost/topmost component would touch
00173          * the edge.  Reduce the move by the edge relief requirement XXX
00174          * and expand the board by the same amount.
00175          */
00176         pad = PCB->minWid * 5;          /* XXX real edge clearance */
00177         dx = -box->X1 + pad;
00178         dy = -box->Y1 + pad;
00179         box->X2 += pad;
00180         box->Y2 += pad;
00181 
00182         /*
00183          * Round move to keep components grid-aligned, then translate the
00184          * upper coordinates into the new space.
00185          */
00186         dx -= dx % (long) PCB->Grid;
00187         dy -= dy % (long) PCB->Grid;
00188         box->X2 += dx;
00189         box->Y2 += dy;
00190 
00191         /*
00192          * Avoid touching any data if there's nothing to do.
00193          */
00194         if (dx == 0 && dy == 0 &&
00195             PCB->MaxWidth == box->X2 && PCB->MaxHeight == box->Y2) {
00196                 return 0;
00197         }
00198 
00199         /* Resize -- XXX cannot be undone */
00200         PCB->MaxWidth = box->X2;
00201         PCB->MaxHeight = box->Y2;
00202 
00203         MoveAll(dx, dy);
00204 
00205         IncrementUndoSerialNumber();
00206         ClearAndRedrawOutput();
00207         SetChangedFlag(1);
00208         return 0;
00209 }
00210 
00211 static HID_Action autocrop_action_list[] = {
00212         {"autocrop", NULL, autocrop, NULL, NULL}
00213 };
00214 
00215 REGISTER_ACTIONS (autocrop_action_list)
00216 
00217 void
00218 hid_autocrop_init()
00219 {
00220         register_autocrop_action_list();
00221 }

Generated on Tue Aug 17 15:28:04 2010 for pcb-plugins by  doxygen 1.4.6-NO